由于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