我希望使我的代码更具可读性,以及使用工具,如IDE代码检查和/或静态代码分析(FindBugs和Sonar),以避免nullpointerexception。许多工具似乎与彼此的@NotNull/@NonNull/ @NonNull注释不兼容,在我的代码中列出所有这些工具会让人难以阅读。有没有什么建议,哪一个是“最好的”?下面是我找到的等价注释列表:

javax.validation.constraints.NotNull Created for runtime validation, not static analysis. documentation edu.umd.cs.findbugs.annotations.NonNull Used by FindBugs (dead project) and its successor SpotBugs static analysis and therefore Sonar (now Sonarqube) FindBugs documentation, SpotBugs documentation javax.annotation.Nonnull This might work with FindBugs too, but JSR-305 is inactive. (See also: What is the status of JSR 305?) source org.jetbrains.annotations.NotNull Used by IntelliJ IDEA IDE for static analysis. documentation lombok.NonNull Used to control code generation in Project Lombok. Placeholder annotation since there is no standard. source, documentation androidx.annotation.NonNull Marker annotation available in Android, provided by annotation package documentation org.eclipse.jdt.annotation.NonNull Used by Eclipse for static code analysis documentation


当前回答

Eclipse也有自己的注释。

org.eclipse.jdt.annotation.NonNull

详情见http://wiki.eclipse.org/JDT_Core/Null_Analysis。

其他回答

如果您正在使用Spring 5。2.执行以下命令:你应该使用Spring注释(org.springframework.lang),因为它们通过@NonNullFields和@NonNullApi注解为你提供了默认的包范围的null检查。当你使用@NonNullFields/@NonNullApi时,你甚至不会与来自其他依赖的其他NotNull/NonNull注释发生冲突。注释必须用在一个名为package-info.java的文件中,该文件位于包的根目录下:

@NonNullFields
@NonNullApi
package org.company.test;

要排除null检查中的某些字段、参数或返回值,只需显式地使用@Nullable注释。而不是使用@NonNullFields/@NonNullApi,你也可以在任何地方设置@NonNull,但可能更好的是在默认情况下使用@NonNullFields/@NonNullApi激活null检查,并且只使用@Nullable执行特定的异常。

IDE (Intellij)将突出显示违反null条件的代码。如果设置正确,每个开发人员都可以假设字段、参数和返回值必须不是空,除非有@Nullable注释。要了解更多信息,请查看这篇文章。

我非常喜欢检查器框架,它是类型注释(JSR-308)的实现,用于实现像null检查器这样的缺陷检查器。我并没有尝试其他任何方法进行比较,但我对这个实现感到满意。

我没有加入提供该软件的组织,但我是它的粉丝。

我喜欢这个系统的四个方面:

It has a defect checkers for nullness (@Nullable), but also has ones for immutability and interning (and others). I use the first one (nullness) and I'm trying to get into using the second one (immutability/IGJ). I'm trying out the third one, but I'm not certain about using it long term yet. I'm not convinced of the general usefulness of the other checkers yet, but its nice to know that the framework itself is a system for implementing a variety of additional annotations and checkers. The default setting for nullness checking works well: Non-null except locals (NNEL). Basically this means that by default the checker treats everyhing (instance variables, method parameters, generic types, etc) except local variables as if they have a @NonNull type by default. Per the documentation: The NNEL default leads to the smallest number of explicit annotations in your code. You can set a different default for a class or for a method if NNEL doesn't work for you. This framework allows you to use with without creating a dependency on the framework by enclosing your annotations in a comment: e.g. /*@Nullable*/. This is nice because you can annotate and check a library or shared code, but still be able to use that library/shared coded in another project that doesn't use the framework. This is a nice feature. I've grown accustom to using it, even though I tend to enable the Checker Framework on all my projects now. The framework has a way to annotate APIs you use that aren't already annotated for nullness by using stub files.

只是指出Java验证API (javax.validation.constraints.*)没有提供@Nullable注释,这在静态分析上下文中非常有价值。这对于运行时bean验证是有意义的,因为这是Java中任何非基本字段的默认值(即没有需要验证/强制的内容)。为达到上述目的,应权衡备选方案。

Another option is the annotations provided with ANTLR 4. Following Pull Request #434, the artifact containing the @NotNull and @Nullable annotations includes an annotation processor that produces compile-time errors and/or warnings in the event one of these attributes is misused (for example, if both are applied to the same item, or if @Nullable is applied to item with a primitive type). The annotation processor provides additional assurance during the software development process that the information conveyed by the application of these annotations is accurate, including in cases of method inheritance.

由于JSR 305(其目标是标准化@NonNull和@Nullable)已经休眠了好几年,恐怕没有好的答案。我们所能做的就是找到一个务实的解决办法,我的办法是:

语法

从纯粹的风格角度来看,我想避免任何IDE,框架或任何工具包,除了Java本身。

这就排除了:

android.support.annotation edu.umd.cs.findbugs.annotations org.eclipse.jdt.annotation org.jetbrains.annotations org.checkerframework.checker.nullness.qual lombok。null

这使得我们只能使用javax.validation.constraints或javax.annotation。 前者随JEE一起提供。如果这比javax更好。注释可能最终随JSE一起出现,也可能永远不会出现,这是一个有争议的问题。 我个人更喜欢javax。注释,因为我不喜欢JEE依赖。

这就留给我们

javax.annotation

这也是最短的一个。

只有一种语法会更好:java.annotation.Nullable。随着其他课程的毕业 从javax到Java,过去的javax。注释会 向正确的方向迈出一步。

实现

我希望它们都有基本相同的琐碎实现, 但一项详细的分析表明,事实并非如此。

首先是相似之处:

@NonNull注释都有一行

public @interface NonNull {}

除了

它将其命名为@NotNull,并有一个简单的实现 javax。具有较长实现的注释 也叫@NotNull,并且有一个实现

@Nullable注释都有一行

public @interface Nullable {}

除了(再次)org.jetbrains.annotations及其琐碎的实现。

对于差异:

一个引人注目的问题是

javax.annotation javax.validation.constraints org.checkerframework.checker.nullness.qual

都有运行时注释(@Retention(runtime)),而

android.support.annotation edu.umd.cs.findbugs.annotations org.eclipse.jdt.annotation org.jetbrains.annotations

只是编译时(@Retention(CLASS))。

如本文所述,SO回答了运行时注释的影响 比人们想象的要小,但他们有好处吗 使工具能够执行运行时检查的 编译时1。

另一个重要的区别是代码中注释的使用位置。 有两种不同的方法。一些包使用JLS 9.6.4.1样式上下文。下表给出了概述:

Package FIELD METHOD PARAMETER LOCAL_VARIABLE
android.support.annotation ✔️ ✔️ ✔️
edu.umd.cs.findbugs.annotations ✔️ ✔️ ✔️ ✔️
org.jetbrains.annotation ✔️ ✔️ ✔️ ✔️
lombok ✔️ ✔️ ✔️ ✔️
javax.validation.constraints ✔️ ✔️ ✔️

org.eclipse.jdt。注释、javax。Annotation和org.checkerframework.checker. nullnness .qual使用中定义的上下文 JLS 4.11,在我看来这是正确的方法。

这就留给我们

javax.annotation org.checkerframework.checker.nullness.qual

在这一轮。

Code

为了帮助您自己进一步比较细节,我在下面列出了每个注释的代码。 为了便于比较,我删除了注释、导入和@Documented注释。 (除了Android包中的类,它们都有@Documented)。 我对行和@Target字段进行了重新排序,并规范了限定条件。

package android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}

package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}

package javax.annotation;
@TypeQualifier
@Retention(RUNTIME)
public @interface Nonnull {
    When when() default When.ALWAYS;
    static class Checker implements TypeQualifierValidator<Nonnull> {
        public When forConstantValue(Nonnull qualifierqualifierArgument,
                Object value) {
            if (value == null)
                return When.NEVER;
            return When.ALWAYS;
        }
    }
}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf(MonotonicNonNull.class)
@ImplicitFor(
    types = {
        TypeKind.PACKAGE,
        TypeKind.INT,
        TypeKind.BOOLEAN,
        TypeKind.CHAR,
        TypeKind.DOUBLE,
        TypeKind.FLOAT,
        TypeKind.LONG,
        TypeKind.SHORT,
        TypeKind.BYTE
    },
    literals = {LiteralKind.STRING}
)
@DefaultQualifierInHierarchy
@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
@DefaultInUncheckedCodeFor({TypeUseLocation.PARAMETER, TypeUseLocation.LOWER_BOUND})
public @interface NonNull {}

为了完整起见,下面是@Nullable的实现:

package android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}

package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}

package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf({})
@ImplicitFor(
    literals = {LiteralKind.NULL},
    typeNames = {java.lang.Void.class}
)
@DefaultInUncheckedCodeFor({TypeUseLocation.RETURN, TypeUseLocation.UPPER_BOUND})
public @interface Nullable {}

下面两个包没有@Nullable,所以我分别列出它们;Lombok有一个非常无聊的@NonNull。 在javax.validation.constraints中@NonNull实际上是一个@NotNull 而且它的实现时间较长。

package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package javax.validation.constraints;
@Retention(RUNTIME)
@Target({ FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Constraint(validatedBy = {})
public @interface NotNull {
    String message() default "{javax.validation.constraints.NotNull.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default {};
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        NotNull[] value();
    }
}

支持

根据我的经验,javax。注释至少被Eclipse和Checker框架开箱即用所支持。

总结

我的理想注释是java。注释语法与检查器框架实现。

如果你不打算使用检查器框架,javax。注释(JSR-305)仍然是目前最好的选择。

如果您愿意购买检查器框架,请使用 org.checkerframework.checker.nullness.qual。


来源

android.support.annotation from android-5.1.1_r1.jar edu.umd.cs.findbugs.annotations from findbugs-annotations-1.0.0.jar org.eclipse.jdt.annotation from org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar org.jetbrains.annotations from jetbrains-annotations-13.0.jar javax.annotation from gwt-dev-2.5.1-sources.jar org.checkerframework.checker.nullness.qual from checker-framework-2.1.9.zip lombok from lombok commit f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4 javax.validation.constraints from validation-api-1.0.0.GA-sources.jar