我希望使我的代码更具可读性,并使用IDE代码检查和/或静态代码分析(FindBugs和Sonar)等工具来避免NullPointerExceptions.许多工具似乎与彼此不兼容的@NotNull / @NonNull / @Nonnull注释并列出我的代码中的所有这些工具都很难阅读.有什么建议是“最好的”吗?这是我发现的等效注释列表:
> javax.validation.constraints.NotNull
创建用于运行时验证,而不是静态分析.
documentation
> edu.umd.cs.findbugs.annotations.NonNull
由Findbugs静态分析使用,因此声纳(现在Sonarqube)
documentation
> javax.annotation.Nonnull
这可能也适用于Findbugs,但JSR-305处于非活动状态. (另见:What is the status of JSR 305?)
source
> org.jetbrains.annotations.NotNull
由IntelliJ IDEA IDE用于静态分析.
documentation
> lombok.NonNull
用于控制Project Lombok中的代码生成.
占位符注释,因为没有标准.
source,
documentation
> android.support.annotation.NonNull
Android中提供的标记注释,由support-annotations包提供
documentation
> org.eclipse.jdt.annotation.NonNull
由Eclipse用于静态代码分析
documentation
解决方法:
自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
这给我们留下了javax.validation.constraints或javax.annotation.
前者配有JEE.如果这比javax.annotation更好,这可能最终会出现在JSE中,或者从来没有出现过,这是一个有争议的问题.
我个人更喜欢javax.annotation,因为我不喜欢JEE依赖.
这让我们失望了
javax.annotation中
这也是最短的一个.
只有一种语法更好:java.annotation.Nullable.随着其他包的毕业
从javax到java过去,javax.annotation会
迈出正确方向的一步.
履行
我希望他们都有基本相同的琐碎实现,
但详细的分析表明,事实并非如此.
首先是相似之处:
@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)).
如this SO answer所述,运行时注释的影响
比人们想象的要小,但它们有好处
启用运行时检查的工具除了
编译时间.
另一个重要的区别是在代码中可以使用注释.
有两种不同的方法.某些包使用JLS 9.6.4.1样式上下文.下表给出了概述:
FIELD METHOD PARAMETER LOCAL_VARIABLE android.support.annotation X X X edu.umd.cs.findbugs.annotations X X X X org.jetbrains.annotation X X X X lombok X X X X javax.validation.constraints X X X
org.eclipse.jdt.annotation,javax.annotation和org.checkerframework.checker.nullness.qual使用在中定义的上下文
JLS 4.11,在我看来是正确的方法.
这让我们失望了
> javax.annotation
> org.checkerframework.checker.nullness.qual
在这一轮.
码
为了帮助您自己比较更多详细信息,我列出了下面每个注释的代码.
为了便于比较,我删除了注释,导入和@Documented注释.
(他们都有@Documented,除了Android包中的类).
我重新排序了行和@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.annotation至少得到Eclipse和Checker Framework的支持.
摘要
我理想的注释是带有Checker Framework实现的java.annotation语法.
如果您不打算使用Checker Framework,那么javax.annotation(JSR-305)仍然是您最好的选择.
如果您愿意购买Checker Framework,请使用
他们的org.checkerframework.checker.nullness.qual.
来源
> android-5.1.1_r1.jar中的android.support.annotation
>来自findbugs-annotations-1.0.0.jar的edu.umd.cs.findbugs.annotations
> org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar中的org.eclipse.jdt.annotation
>来自jetbrains-annotations-13.0.jar的org.jetbrains.annotations
>来自gwt-dev-2.5.1-sources.jar的javax.annotation
> checker-framework-2.1.9.zip中的org.checkerframework.checker.nullness.qual
>来自lombok的lombok提交f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
>来自validation-api-1.0.0.GA-sources.jar的javax.validation.constraints