我应该使用哪个@NotNull Java注释?

jax*_*zin 918 java ide null annotations nullpointerexception

我希望使我的代码更具可读性,并使用IDE代码检查和/或静态代码分析(FindBugs和Sonar)等工具来避免NullPointerExceptions.许多工具似乎与彼此的@NotNull/ @NonNull/ @Nonnull注释不兼容,并列出我的代码中的所有这些工具都很难阅读.有什么建议是"最好的"吗?这是我发现的等效注释列表:

  • javax.validation.constraints.NotNull
    创建用于运行时验证,而不是静态分析.
    文件

  • edu.umd.cs.findbugs.annotations.NonNull
    Findbugs静态分析使用,因此Sonar(现为Sonarqube)
    文档

  • javax.annotation.Nonnull
    这可能也适用于Findbugs,但JSR-305处于非活动状态.(另请参阅:JSR 305的状态是什么?) 来源

  • org.jetbrains.annotations.NotNull
    由IntelliJ IDEA IDE用于静态分析.
    文件

  • lombok.NonNull
    用于控制Project Lombok中的代码生成.
    占位符注释,因为没有标准.
    来源, 文档

  • android.support.annotation.NonNull
    Android中提供的标记注释,由support-annotations包
    文档提供

  • org.eclipse.jdt.annotation.NonNull
    Eclipse用于静态代码分析
    文档

Lud*_*erl 154

由于甲骨文目前决定不对 @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 {}
Run Code Online (Sandbox Code Playgroud)

除了

  • org.jetbrains.annotations将其称为@NotNull,并且具有简单的实现
  • javax.annotation具有更长的实现
  • javax.validation.constraints也称它为@NotNull并具有实现

@Nullable注释都有这一行

public @interface Nullable {}
Run Code Online (Sandbox Code Playgroud)

除了(再次)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)).

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

另一个重要的区别是,其中在所述代码可用于注释.有两种不同的方法.某些包使用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 {}
Run Code Online (Sandbox Code Playgroud)
package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}
Run Code Online (Sandbox Code Playgroud)
package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}
Run Code Online (Sandbox Code Playgroud)
package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}
Run Code Online (Sandbox Code Playgroud)
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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
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 {}
Run Code Online (Sandbox Code Playgroud)

为了完整性,这里是@Nullable实现:

package android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}
Run Code Online (Sandbox Code Playgroud)
package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}
Run Code Online (Sandbox Code Playgroud)
package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}
Run Code Online (Sandbox Code Playgroud)
package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}
Run Code Online (Sandbox Code Playgroud)
package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}
Run Code Online (Sandbox Code Playgroud)
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 {}
Run Code Online (Sandbox Code Playgroud)

以下两个包没有@Nullable,所以我单独列出它们lombok有一个非常无聊的@NonNull.在javax.validation.constraints中,@ NonNull实际上是@NotNull,它有一个很长的实现.

package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}
Run Code Online (Sandbox Code Playgroud)
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();
    }
}
Run Code Online (Sandbox Code Playgroud)

支持

从我的经验来看,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

  • 反对`javax.annotation`的另一个观点是它会导致Java 9出现问题,因为其他模块也提供了该包中的类(jax-ws). (10认同)
  • @kevinarpe:Findbugs项目已经死了,后续项目Spotbugs正在删除这些注释:https://github.com/spotbugs/spotbugs/pull/180 (7认同)
  • `javax.annotation`的缺点是它是a)基于死的JSR,b)很难找到只提供注释并被维护的工件.来自findbugs的那个不是:https://search.maven.org/#search|gav|1 |g%3A%22com.google.code.findbugs%22%20AND%20a%3A%22jsr305%22 (5认同)
  • [JSR 305](https://jcp.org/en/jsr/detail?id=305),它已将`javax.annotation.NonNull`标准化,但由于其规范领先者AWOL而从未完成。它与Oracle的任何决定无关。 (4认同)
  • 不使用jsr305.jar的另一个原因是,它显然违反了Oracle Java二进制许可证:https://github.com/google/guava/issues/2960 (4认同)
  • FindBugs `Nullable` 有一个问题:我认为它的含义与您认为的含义不同。它并不意味着“该字段可能包含 null,您需要检查它”。相反,它的意思是“将此字段视为根本没有注释”。表示“检查 null”的 FindBugs 注释被命名为“@CheckForNull”。 (3认同)
  • 如今,Checker 框架似乎得到了广泛的支持。你能分辨出 javax 注释和 checker.qual 之间的实际区别吗?例如,Spotbugs 不能使用 checker.qual 注释 [现在](https://github.com/spotbugs/spotbugs/issues/523)? (2认同)
  • 较新的项目可能应该使用 [jakarta.annotation-api](https://search.maven.org/artifact/jakarta.annotation/jakarta.annotation-api/2.1.0-B1/jar) (2认同)
  • 不再需要使用 JavaEE 的“javax”前缀。JakartaEE 10 应该有“@Nonnull”和“@Nullable”注释,它们是 jakarta.annotation-api 依赖项的一部分。我正在写,它已经可以在 Maven 上下载 beta 版本:`jakarta.annotation-api:2.1.0-B1`。来源:https://github.com/eclipse-ee4j/common-annotations-api/issues/89 (2认同)
  • 您可以更新问题以包含 [jakarta.annotations](https://jakarta.ee/specations/annotations/2.1/annotations-spec-2.1#annotations) 吗? (2认同)

Ber*_*t F 87

我非常喜欢Checker Framework,它是类型注释(JSR-308)的实现,用于实现缺陷检查器之类的缺陷检查器.我还没有真正尝试任何其他人提供任何比较,但我对这个实现感到满意.

我不是提供该软件的团体的附属机构,但我是粉丝.

我喜欢这个系统的四件事:

  1. 它有一个缺陷跳棋NULL的含量(@Nullable),但也有药粥不变性实习(及其他).我使用第一个(nullness),我正在尝试使用第二个(immutability/IGJ).我正在尝试第三个,但我不确定长期使用它.我还不相信其他检查器的一般用处,但很高兴知道框架本身是一个用于实现各种附加注释和检查器的系统.

  2. nullness检查默认设置很有效:除了本地(NNEL)之外的非null.基本上这意味着默认情况下,检查器会处理除局部变量之外的每个(实例变量,方法参数,泛型类型等),就像它们默认具有@NonNull类型一样.根据文件:

    NNEL默认值会导致代码中显式注释的数量最少.

    如果NNEL不适合您,您可以为类或方法设置不同的默认值.

  3. 通过将注释括在注释中,此框架允许您在不创建对框架的依赖的情况下使用:例如/*@Nullable*/.这很好,因为您可以注释和检查库或共享代码,但仍然能够在不使用框架的另一个项目中使用该库/共享编码.这是一个很好的功能.我已经习惯使用它,即使我现在倾向于在我的所有项目中启用Checker Framework.

  4. 该框架有一种方法可以使用存根文件来注释您使用的尚未注释为null的API.

  • 根据[FAQ](http://types.cs.washington.edu/checker-framework/current/checkers-manual.html#credits):"更宽松的MIT许可证适用于您可能希望包含在的代码中你自己的程序,比如注释." (13认同)
  • 看起来很棒,我想用它,但不能.为何选择GPL?难道不是LGPL吗? (3认同)
  • [Oracle Java 教程](https://docs.oracle.com/javase/tutorial/java/annotations/type_annotations.html) 中还建议使用 Checker Framework。 (2认同)

Sam*_*num 53

我使用IntelliJ,因为我主要关注IntelliJ标记可能产生NPE的东西.我同意在JDK中没有标准注释令人沮丧.有关添加它的讨论,它可能会成为Java 7.在这种情况下,还有一个可供选择!

  • 更新:IntelliJ现在支持所有上述代码突出显示注释,因此您不再受限于IntelliJ的注释:http://blogs.jetbrains.com/idea/2011/03/more-flexible-and-configurable-nullublenotnull -annotations / (61认同)
  • Eclipse Juno也是如此! (29认同)
  • `javax.annotation.Nonnull`被广泛接受,不是吗? (5认同)
  • @Trejkaz自2016.3起,它为所有这些创建了运行时检查. (3认同)

Ste*_*n C 32

根据Java 7特性列表, JSR-308类型注释被推迟到Java 8.甚至没有提到JSR-305注释.

在最新的JSR-308草案的附录中有关于JSR-305状态的一些信息.这包括观察到JSR-305注释似乎被放弃了.JSR-305页面也将其显示为"非活动".

同时,实用的答案是使用最广泛使用的工具支持的注释类型......并准备好在情况发生变化时更改它们.


事实上,JSR-308没有定义任何注释类型/类,看起来他们认为它超出了范围.(鉴于JSR-305的存在,它们是正确的).

但是,如果JSR-308真的看起来像是在Java 8中,那么如果对JSR-305的兴趣再次兴起,我也不会感到惊讶.AFAIK,JSR-305团队尚未正式放弃他们的工作.他们刚刚安静了2年多.

有趣的是,Bill Pugh(JSR-305的技术主管)是FindBugs背后的人之一.

  • @pst - 目前的时间表是Java 8将于2013年9月发布的一般版本 - http://www.infoq.com/news/2012/04/jdk-8-milestone-release-dates (4认同)
  • 那已经下滑到2014年3月 - http://openjdk.java.net/projects/jdk8/.JSR 308包含在构建M7中(参见"104 - Java类型的注释"). (2认同)

Jam*_*ald 26

对于Android项目,您应该使用android.support.annotation.NonNullandroid.support.annotation.Nullable.支持库中提供了这些以及其他有用的Android特定注释.

来自http://tools.android.com/tech-docs/support-annotations:

支持库本身也使用这些注释进行了注释,因此作为支持库的用户,Android Studio已经检查了您的代码并根据这些注释标记了潜在的问题.

  • 顺便说一句,Android Studio 也支持带有 `javax.annotation.*` 注释的 jsr305 (3认同)
  • 为该建议提供理由是有用的。 (2认同)
  • http://tools.android.com/tech-docs/support-annotations"支持库本身也注释了这些注释,因此作为支持库的用户,Android Studio已经检查了您的代码并标记了潜在的问题基于这些注释." (2认同)

Bru*_*ard 19

如果有人只是在寻找IntelliJ类:你可以从maven存储库中获取它们

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 
Run Code Online (Sandbox Code Playgroud)


Gil*_*ili 18

JSR305和FindBugs由同一个人创作.两者都维护得很差,但它们是标准的,并得到所有主要IDE的支持.好消息是它们按原样运作良好.

以下是默认情况下如何将@Nonnull应用于所有类,方法和字段.请参阅/sf/answers/932367901//sf/answers/647961681/

  1. 限定 @NotNullByDefault
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;


    /**
     * This annotation can be applied to a package, class or method to indicate that the class fields,
     * method return types and parameters in that element are not null by default unless there is: <ul>
     * <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
     * case the annotation of the corresponding parameter in the superclass applies) <li> there is a
     * default parameter annotation applied to a more tightly nested element. </ul>
     * <p/>
     * @see https://stackoverflow.com/a/9256595/14731
     */
    @Documented
    @Nonnull
    @TypeQualifierDefault(
    {
        ElementType.ANNOTATION_TYPE,
        ElementType.CONSTRUCTOR,
        ElementType.FIELD,
        ElementType.LOCAL_VARIABLE,
        ElementType.METHOD,
        ElementType.PACKAGE,
        ElementType.PARAMETER,
        ElementType.TYPE
    })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NotNullByDefault
    {
    }
Run Code Online (Sandbox Code Playgroud)

2.将注释添加到每个包: package-info.java

@NotNullByDefault
package com.example.foo;
Run Code Online (Sandbox Code Playgroud)

更新:截至2012年12月12日,JSR 305被列为"休眠".根据文件:

被执行委员会评为"休眠"的JSR,或者已经达到其自然寿命终结的JSR.

看起来JSR 308 正在进入JDK 8,尽管JSR没有定义@NotNull,但随之而来Checkers Framework.在撰写本文时,由于此错误,Maven插件无法使用:https://github.com/typetools/checker-framework/issues/183

  • maven的showstopper问题是固定的.所以这应该是一个选择. (2认同)

Cri*_*tan 16

JSpecify将是可行的方法(当它准备好时)。事实上:他们的演讲积极链接到这个问题,并明确指出他们的目标是最终得到一个好的答案。

它的主要参与者有 Android、Guava 和 Kotlin。

  • 同时 v0.3.0 发布了,并提供了很好的用户指南:https://jspecify.dev/docs/user-guide。对于“@NullMarked”的“专业”功能,IntelliJ IDE 支持并不完全存在,但它将得到修复:https://youtrack.jetbrains.com/issue/IDEA-323691/JSpecifys-NullMarked-not-considered-for -Not-annotated-method-overrides-method-annotated-with-NotNull-inspection(请投票) (2认同)

Hor*_*ux7 12

Eclipse也有自己的注释.

org.eclipse.jdt.annotation.NonNull
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅http://wiki.eclipse.org/JDT_Core/Null_Analysis.


Oph*_*itz 11

只是指出Java Validation API(javax.validation.constraints.*)没有附带@Nullable注释,这在静态分析上下文中非常有价值.它对运行时bean验证很有意义,因为这是Java中任何非原始字段的默认值(即无需验证/强制执行).出于上述目的,应该考虑替代方案.


tkr*_*use 10

区分静态分析和运行时分析.对内部事物使用静态分析,对代码的公共边界使用运行时分析.

对于不应该为null的东西:

  • 运行时检查:使用"if(x == null)..."(零依赖)或@ javax.validation.NotNull(使用bean验证)或@ lombok.NonNull(简单和简单)或guavas Preconditions.checkNotNull(.. .)

    • 对于方法返回类型,仅使用Optional(仅限).Java8或Guava.
  • 静态检查:使用@NonNull注释

  • 在适合的地方,在类或包级别使用@ ... NonnullByDefault注释.自己创建这些注释(示例很容易找到).
    • 否则,在方法返回时使用@ ... CheckForNull以避免NPE

这应该给出最好的结果:IDE中的警告,Findbugs和checkerframework的错误,有意义的运行时异常.

不要指望静态检查是成熟的,它们的命名不是标准化的,不同的库和IDE会以不同的方式对待它们,忽略它们.JSR305 javax.annotations.*类看起来像标准,但它们不是,它们会导致Java9 +的拆分包.

一些说明解释:

  • 了findBUGs/spotbugs/JSR305注解与包javax.validation*冲突与Java9 +其他模块,也可能违反许可证的Oracle
  • Spotbugs注释仍然依赖于编译时的jsr305/findbugs注释(在撰写本文时https://github.com/spotbugs/spotbugs/issues/421)
  • jetbrains @NotNull名称与@ javax.validation.NotNull冲突.
  • JetBrains公司,用于静态检查Eclipse或checkersframework标注有优势javax.annotations,他们不与Java9和更高的其他模块冲突
  • @ javax.annotations.Nullable并不意味着Findbugs/Spotbugs你(或你的IDE)认为它意味着什么.Findbugs将忽略它(在成员上).可悲,但却是真的(https://sourceforge.net/p/findbugs/bugs/1181)
  • 对于IDE外部的静态检查,存在2个免费工具:Spotbugs(以前称为Findbugs)和checkersframework.
  • Eclipse库有@NonNullByDefault,jsr305只有@ParametersAreNonnullByDefault.这些仅仅是将基础注释应用于包(或类)中的所有东西的便利包装器,您可以轻松地创建自己的.这可以在包装上使用.这可能与生成的代码(例如lombok)冲突.
  • Eclipse jdt注释不适用于静态方法返回和其他一些情况
  • 对于与其他人共享的库,应该避免使用lombok作为导出的依赖项,传递依赖性越小越好
  • 使用Bean验证框架功能强大,但需要很高的开销,因此过度杀戮只是为了避免手动空值检查.
  • 对字段和方法参数使用Optional是有争议的(您可以轻松找到有关它的文章)
  • Android null注释是Android支持库的一部分,它们带有很多其他类,并且不能很好地与其他注释/工具一起使用

在Java9之前,这是我的建议:

// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;


// file: PublicApi
package example;

public interface PublicApi {

    Person createPerson(
        // NonNull by default due to package-info.java above
        String firstname,
        String lastname);
}

// file: PublicApiImpl
public class PublicApiImpl implements PublicApi {
    public Person createPerson(
            // In Impl, handle cases where library users still pass null
            @Nullable String firstname, // Users  might send null
            @Nullable String lastname // Users might send null
            ) {
        if (firstname == null) throw new IllagalArgumentException(...);
        if (lastname == null) throw new IllagalArgumentException(...);
        return doCreatePerson(fistname, lastname, nickname);
    }

    @NonNull // Spotbugs checks that method cannot return null
    private Person doCreatePerson(
             String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
             String lastname,
             @Nullable String nickname // tell Spotbugs null is ok
             ) {
         return new Person(firstname, lastname, nickname);
    }

    @CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
    private Person getNickname(
         String firstname,
         String lastname) {
         return NICKNAMES.get(firstname + ':' + lastname);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,有没有办法让Spotbugs提高时,可为空的方法参数解除引用警告(在写作,Spotbugs的3.1版本的时间).也许checkerframework可以做到这一点.


mor*_*wai 9

较新的项目可能应该使用jakarta.annotation-apijakarta.annotation包)。
它从现在只读的javax.annotation 存储库链接,并融入新的雅加达生态系统,旨在使社区摆脱所有javax相关的麻烦。

  • Jakarta 注释 API 是未来:“jakarta.annotation.Nonnull”和“jakarta.annotation.Nullable”。它们是标准的且具有通用语义。再见 Javax Validation API 注释! (3认同)

noa*_*mtm 8

这里已经有太多答案了,但是 (a) 现在已经是 2019 年了,仍然没有“标准”,Nullable并且 (b) 没有其他答案引用 Kotlin。

对 Kotlin 的引用很重要,因为 Kotlin 与 Java 100% 可互操作,并且它具有核心 Null Safety 功能。当调用 Java 库时,它可以利用这些注释让 Kotlin 工具知道 Java API 是否可以接受或返回null.

据我所知,唯一Nullable与 Kotlin 兼容的软件包是org.jetbrains.annotationsandroid.support.annotation(现在androidx.annotation)。后者仅与 Android 兼容,因此不能在非 Android JVM/Java/Kotlin 项目中使用。然而,JetBrains 软件包可以在任何地方使用。

因此,如果您开发的 Java 包也应该在 Android 和 Kotlin 中工作(并且受 Android Studio 和 IntelliJ 支持),那么您的最佳选择可能是 JetBrains 包。

行家:

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations-java5</artifactId>
    <version>15.0</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

摇篮:

implementation 'org.jetbrains:annotations-java5:15.0'
Run Code Online (Sandbox Code Playgroud)

  • 嗯,这另有说明:https://kotlinlang.org/docs/reference/java-interop.html#nullability-annotations (4认同)

Wer*_*eil 7

不幸的是,这里JSR 308不会添加比这个项目本地Not Null建议更多的值

Java 8不会带有单个默认注释或其自己的Checker框架.与Find-bugs类似JSR 305,这个JSR很少由一小部分学术团队维护.

它背后没有任何商业力量,因此现在JSR 308推出EDR 3(早期草案评论JCP),虽然Java 8应该在不到6个月内发货:-O类似于310顺便说一句.但与308 Oracle现在远离其创始人,以尽量减少对Java平台的伤害的人不同.

每个项目,供应商和学术类就像后面的那些Checker Framework,JSR 308并将创建自己的专有检查器注释.

制作源代码不兼容几年来,一直到有一些流行的妥协可能被发现,也许加入Java 9或者10,或者通过类似的框架Apache CommonsGoogle Guava;-)


Shu*_*ary 7

Android的

这个答案是Android特有的.Android有支持包叫做support-annotations.这提供了几十种Android的具体注释,还提供了常见的一样NonNull,Nullable等等.

要添加support-annotations包,请在build.gradle中添加以下依赖项:

compile 'com.android.support:support-annotations:23.1.1'
Run Code Online (Sandbox Code Playgroud)

然后使用:

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}
Run Code Online (Sandbox Code Playgroud)


bvd*_*vdb 6

如果您正在从事一个大项目,您可能最好创建自己的 @Nullable和/或@NotNull注释。

例如:

@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD,
                              java.lang.annotation.ElementType.METHOD,    
                              java.lang.annotation.ElementType.PARAMETER,
                              java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable 
{
}
Run Code Online (Sandbox Code Playgroud)

如果您使用正确的保留策略,则注释在运行时将不可用。从这个角度来看,这只是一个内部的事情。

尽管这不是一门严格的科学,但我认为使用内部类是最有意义的。

  • 这是一个内在的事情。(没有功能或技术影响)
  • 有很多很多很多用途。
  • IntelliJ 等 IDE 支持自定义@Nullable/@NotNull注释。
  • 大多数框架也更喜欢使用自己的内部版本。

其他问题(见评论):

如何在 IntelliJ 中进行配置?

单击IntelliJ状态栏右下角的“警察”。然后在弹出窗口中单击“配置检查”。下一个 ... 配置注释

  • @user1244932 你的意思是IntelliJ IDEA吗?您可以配置它用于静态分析的可空性注释。我不确切知道在哪里,但定义它们的一个地方是“文件&gt;设置&gt;构建、执行、部署&gt;编译器”,并且有一个按钮“配置注释...”。 (3认同)

Art*_*ken 5

在等待上游排序(Java 8?)的同时,您还可以定义自己的项目本地@NotNull@Nullable注释.如果您正在使用Java SE,这在默认情况下javax.validation.constraints 不可用的情况下也很有用.

import java.lang.annotation.*;

/**
 * Designates that a field, return value, argument, or variable is
 * guaranteed to be non-null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface NotNull {}

/**
 * Designates that a field, return value, argument, or variable may be null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface Nullable {}
Run Code Online (Sandbox Code Playgroud)

这无疑主要是出于装饰性或面向未来的目的,因为上述内容显然本身并未对这些注释的静态分析提供任何支持.


Moz*_*ini 5

在 Java 8 中有另一种方法可以做到这一点。我正在做两件事来完成我所需要的:

  1. 通过将可为空的字段与 java.util.Optional
  2. 在构造时检查所有不可为空的字段是否为空 java.util.Objects.requireNonNull

例子:

编辑:忽略第一个示例,我只是作为评论对话的上下文离开这里。在此之后跳至推荐选项(第二个代码块)。

    import static java.util.Objects.requireNonNull;

    public class Role {

      private final UUID guid;
      private final String domain;
      private final String name;
      private final Optional<String> description;

      public Role(UUID guid, String domain, String name, Optional<String> description) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);
        this.description = requireNonNull(description);
      }
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,我们甚至需要在使用 java 8 时进行注释吗?

编辑:我后来发现有些人认为Optional在参数中使用是一种不好的做法,这里有一个关于优点和缺点的很好的讨论为什么 Java 8 的 Optional 不能用于参数

推荐选项,因为在参数中使用 Optional 不是最佳实践,我们需要 2 个构造函数:

  //Non null description
  public Role(UUID guid, String domain, String name, String description) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);

        // description will never be null
        requireNonNull(description);

        // but wrapped with an Optional
        this.description = Optional.of(description);
      }

  // Null description is assigned to Optional.empty
  public Role(UUID guid, String domain, String name) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);
        this.description = Optional.empty();
      }
Run Code Online (Sandbox Code Playgroud)

  • 我仍然可以编写此代码:`new Role(null,null,null,null);`。通过注释,我的 IDE 和静态分析将警告不能将 null 传递到这些参数中。没有它,直到我运行代码我才发现。这就是注释的价值。 (4认同)
  • 我也处于开发人员可以使用他们喜欢的任何 IDE 或文本编辑器的环境中,它们不是相互排斥的。然后,我们还将 maven-pmd-plugin 和/或 SonarQube 集成到构建过程中,以鼓励和突出显示,甚至关闭预合并的代码质量问题,例如拉取请求。 (2认同)
  • Optional 并不意味着用作方法参数或私有字段。参见例如:https://stuartmarks.wordpress.com/2016/09/27/vjug24-session-on-optional/ (2认同)

wal*_*ros 5

如果您使用 Spring Framework 构建应用程序,我建议使用来自以下依赖项打包的Beans Validation 的javax.validation.constraints.NotNull通信:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

该注解的主要优点是Spring提供了对方法参数和使用.注解的类字段的支持javax.validation.constraints.NotNull。要启用支持,您所需要做的就是:

  1. 提供用于 beans 验证的 api jar 和带有 jsr-303/jsr-349 注释验证器实现的 jar(随 Hibernate Validator 5.x 依赖项一起提供):

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 为 spring 的上下文提供 MethodValidationPostProcessor

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 最后,您用 Spring 注释您的类org.springframework.validation.annotation.Validated,并且验证将由 Spring 自动处理。

例子:

@Service
@Validated
public class MyServiceImpl implements MyService {

  @Override
  public Something doSomething(@NotNull String myParameter) {
        // No need to do something like assert myParameter != null  
  }
}
Run Code Online (Sandbox Code Playgroud)

当您尝试调用方法 doSomething 并传递 null 作为参数值时,spring(通过 HibernateValidator)将抛出ConstraintViolationException。这里不需要手动工作。

您还可以验证返回值。

使用 Beans Validation Framework的另一个重要好处javax.validation.constraints.NotNull是,目前它仍在开发中,并且计划在新版本 2.0 中添加新功能。

关于什么@Nullable?Beans Validation 1.1 中没有类似的内容。好吧,我可以说,如果您决定使用@NotNull,那么所有未注释的内容@NonNull实际上都是“可为空的”,因此@Nullable注释是无用的。

  • 请不要使用它。它用于运行时验证,而不是静态代码分析。有关详细信息,请参阅http://justsomejavaguy.blogspot.com/2011/08/nullable-null-notnull-notnull-nonnull.html。来源:已删除答案,@luis.espinal 获得 219 票。 (2认同)

Mig*_*noz 5

IntelliJ 的好处之一是您不需要使用它们的注释。您可以自己编写,也可以使用您喜欢的任何其他工具。您甚至不限于单一类型。如果您使用的两个库使用不同的@NotNull注释,您可以告诉 IntelliJ 使用它们。为此,请转到“配置检查”,单击“常量条件和异常”检查,然后单击“配置检查”按钮。我尽可能使用 Nullness Checker,因此我设置 IntelliJ 来使用这些注释,但您可以让它与您想要的任何其他工具一起使用。(我对其他工具没有意见,因为我多年来一直使用 IntelliJ 的检查,并且我喜欢它们。)


归档时间:

查看次数:

265279 次

最近记录:

6 年 前