Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
307 views
in Technique[技术] by (71.8m points)

java - 我应该使用哪个@NotNull Java注释?(Which @NotNull Java annotation should I use?)

I'm looking to make my code more readable as well as use tooling like IDE code inspection and/or static code analysis (FindBugs and Sonar) to avoid NullPointerExceptions.

(我希望使我的代码更具可读性,并使用IDE代码检查和/或静态代码分析(FindBugs和Sonar)等工具来避免NullPointerExceptions。)

Many of the tools seem incompatible with each others' @NotNull / @NonNull / @Nonnull annotation and listing all of them in my code would be terrible to read.

(许多工具似乎与彼此的@NotNull / @NonNull / @Nonnull注释不兼容,并且在我的代码中列出所有这些工具都很难阅读。)

Any suggestions of which one is the 'best'?

(有什么建议是“最好的”吗?)

Here is the list of equivalent annotations I've found:

(这是我发现的等效注释列表:)

  ask by jaxzin translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Since JSR 305 (whose goal was to standardize @NonNull and @Nullable) has been dormant for several years, I'm afraid there is no good answer.

(由于JSR 305 (其目标是标准化@NonNull和@Nullable)已经蛰伏了好几年,我担心没有好的答案。)

All we can do is to find a pragmatic solution and mine is as follows:

(我们所能做的就是找到一个实用的解决方案,我的如下:)

Syntax (句法)

From a purely stylistic standpoint I would like to avoid any reference to IDE, framework or any toolkit except Java itself.

(从纯粹的风格角度来看,我想避免任何对IDE,框架或除Java本身之外的任何工具包的引用。)

This rules out:

(这排除了:)

  • android.support.annotation

    (android.support.annotation)

  • edu.umd.cs.findbugs.annotations

    (edu.umd.cs.findbugs.annotations)

  • org.eclipse.jdt.annotation

    (org.eclipse.jdt.annotation)

  • org.jetbrains.annotations

    (org.jetbrains.annotations)

  • org.checkerframework.checker.nullness.qual

    (org.checkerframework.checker.nullness.qual)

  • lombok.NonNull

    (lombok.NonNull)

Which leaves us with either javax.validation.constraints or javax.annotation.

(这给我们留下了javax.validation.constraints或javax.annotation。)

The former comes with JEE.

(前者配有JEE。)

If this is better than javax.annotation, which might come eventually with JSE or never at all, is a matter of debate.

(如果这比javax.annotation更好,这可能最终会出现在JSE中,或者从来没有出现过,这是一个有争议的问题。)

I personally prefer javax.annotation because I wouldn't like the JEE dependency.

(我个人更喜欢javax.annotation,因为我不喜欢JEE依赖。)

This leaves us with

(这让我们失望了)

javax.annotation

(javax.annotation中)

which is also the shortest one.

(这也是最短的一个。)

There is only one syntax which would even be better: java.annotation.Nullable.

(只有一种语法更好:java.annotation.Nullable。)

As other packages graduated from javax to java in the past, the javax.annotation would be a step in the right direction.

(由于过去其他软件包从javax毕业到java,javax.annotation将是朝着正确方向迈出的一步。)

Implementation (履行)

I was hoping that they all have basically the same trivial implementation, but a detailed analysis showed that this is not true.

(我希望它们都具有基本相同的简单实现,但详细的分析表明这不是真的。)

First for the similarities:

(首先是相似之处:)

The @NonNull annotations all have the line

(@NonNull注释都有这一行)

public @interface NonNull {}

except for

(除了)

  • org.jetbrains.annotations which calls it @NotNull and has a trivial implementation

    (org.jetbrains.annotations将其称为@NotNull,并且具有简单的实现)

  • javax.annotation which has a longer implementation

    (javax.annotation具有更长的实现)

  • javax.validation.constraints which also calls it @NotNull and has an implementation

    (javax.validation.constraints也称它为@NotNull并具有实现)

The @Nullable annotations all have the line

(@Nullable注释都有这一行)

public @interface Nullable {}

except for (again) the org.jetbrains.annotations with their trivial implementation.

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

For the differences:

(对于差异:)

A striking one is that

(一个引人注目的是)

  • javax.annotation

    (javax.annotation中)

  • javax.validation.constraints

    (javax.validation.constraints)

  • org.checkerframework.checker.nullness.qual

    (org.checkerframework.checker.nullness.qual)

all have runtime annotations (@Retention(RUNTIME), while

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

  • android.support.annotation

    (android.support.annotation)

  • edu.umd.cs.findbugs.annotations

    (edu.umd.cs.findbugs.annotations)

  • org.eclipse.jdt.annotation

    (org.eclipse.jdt.annotation)

  • org.jetbrains.annotations

    (org.jetbrains.annotations)

are only compile time (@Retention(CLASS)).

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

As described in this SO answer the impact of runtime annotations is smaller than one might think, but they have the benefit of enabling tools to do runtime checks in addition to the compile time ones.

(正如本回答中所述,运行时注释的影响比人们想象的要小,但除了编译时间之外,它们还有使工具能够进行运行时检查的好处。)

Another important difference is where in the code the annotations can be used.

(另一个重要的区别是代码可以使用注释。)

There are two different approaches.

(有两种不同的方法。)

Some packages use JLS 9.6.4.1 style contexts.

(某些包使用JLS 9.6.4.1样式上下文。)

The following table gives an overview:

(下表给出了概述:)

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 and org.checkerframework.checker.nullness.qual use the contexts defined in JLS 4.11, which is in my opinion the right way to do it.

(org.eclipse.jdt.annotation,javax.annotation和org.checkerframework.checker.nullness.qual使用JLS 4.11中定义的上下文,我认为这是正确的方法。)

This leaves us with

(这让我们失望了)

  • javax.annotation

    (javax.annotation中)

  • org.checkerframework.checker.nullness.qual

    (org.checkerframework.checker.nullness.qual)

in this round.

(在这一轮。)

Code (码)

To help you to compare further details yourself I list the code of every annotation below.

(为了帮助您自己比较更多详细信息,我列出了下面每个注释的代码。)

To make comparison easier I removed comments, imports and the @Documented annotation.

(为了便于比较,我删除了注释,导入和@Documented注释。)

(they all had @Documented except for the classes from the Android package).

((他们都有@Documented,除了Android包中的类)。)

I reordered the lines and @Target fields and normalized the qualifications.

(我重新排序了行和@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 {}

For completeness, here are the @Nullable implementations:

(为了完整性,这里是@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 {}

The following two packages have no @Nullable, so I list them separately lombok has a pretty boring @NonNull.

(以下两个包没有@Nullable,所以我单独列出它们lombok有一个非常无聊的@NonNull。)

In javax.validation.constraints the @NonNull is actually a @NotNull and it has a longish implementation.

(在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();
    }
}

Support (支持)

From my experience, javax.annotation is at least supported by Eclipse and the Checker Framework out of the box.

(根据我的经验,Eclipse和开箱即用的Checker Framework至少支持javax.annotation。)

Summary (摘要)

My ideal annotation would


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...