由于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.NonNull
这给我们留下了或.前者附带JEE。如果这比 好,最终可能会与 JSE 一起出现,或者根本不会出现,这是一个有争议的问题。我个人更喜欢,因为我不喜欢JEE依赖关系。javax.validation.constraints
javax.annotation
javax.annotation
javax.annotation
这给我们留下了
javax.annotation
这也是最短的一个。
只有一种语法会更好:.正如过去其他软件包从到不同方向发展的那样,javax.annotation将是朝着正确方向迈出的一步。java.annotation.Nullable
javax
java
实现
我希望它们基本上都有相同的琐碎实现,但详细的分析表明这不是真的。
首先是相似之处:
注释都有行@NonNull
public @interface NonNull {}
除了
-
org.jetbrains.annotations
它调用它并具有一个微不足道的实现@NotNull
-
javax.annotation
它具有更长的实现时间
-
javax.validation.constraints
它也调用它并具有实现@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 答案中所述,运行时注释的影响比人们想象的要小,但它们的好处是,除了编译时检查之外,它们还使工具能够执行运行时检查。
另一个重要的区别是可以在代码中使用注释的位置。有两种不同的方法。某些包使用 JLS 9.6.4.1 样式上下文。下表给出了概述:
包 |
田 |
方法 |
参数 |
LOCAL_VARIABLE |
android.support.annotation |
✔️ |
✔️ |
✔️ |
|
edu.umd.cs.findbugs.annotations |
✔️ |
✔️ |
✔️ |
✔️ |
org.jetbrains.annotation |
✔️ |
✔️ |
✔️ |
✔️ |
龙目岛 |
✔️ |
✔️ |
✔️ |
✔️ |
javax.validation.constraints |
✔️ |
✔️ |
✔️ |
|
org.eclipse.jdt.annotation
,并使用JLS 4.11中定义的上下文,在我看来,这是正确的方法。javax.annotation
org.checkerframework.checker.nullness.qual
这给我们留下了
javax.annotation
org.checkerframework.checker.nullness.qual
在这一轮中。
法典
为了帮助您自己比较更多细节,我在下面列出了每个注释的代码。为了使比较更容易,我删除了注释,导入和注释。(除了Android软件包中的类之外,他们都有)。我对线条和字段进行了重新排序,并对资格进行了规范化。@Documented
@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
@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();
}
}
支持
根据我的经验,至少是Eclipse和Checker框架开箱即用的支持。javax.annotation
总结
我理想的注释是使用Checker Framework实现的语法。java.annotation
如果你不打算使用Checker框架,javax.annotation
(JSR-305)仍然是你目前最好的选择。
如果您愿意购买Checker框架,只需使用他们的.org.checkerframework.checker.nullness.qual
来源
-
android.support.annotation
从android-5.1.1_r1.jar
-
edu.umd.cs.findbugs.annotations
从findbugs-annotations-1.0.0.jar
-
org.eclipse.jdt.annotation
从org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
-
org.jetbrains.annotations
从jetbrains-annotations-13.0.jar
-
javax.annotation
从gwt-dev-2.5.1-sources.jar
-
org.checkerframework.checker.nullness.qual
从checker-framework-2.1.9.zip
-
lombok
从提交lombok
f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
-
javax.validation.constraints
从validation-api-1.0.0.GA-sources.jar