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

时间:2011-02-10 22:05:35

标签: java nullpointerexception null annotations ide

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

22 个答案:

答案 0 :(得分:120)

由于Oracle decided not to standardize @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

答案 1 :(得分:85)

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

我不隶属于提供软件的团队,但我是粉丝。

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

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

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

      

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

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

  3. 此框架允许您通过将注释括在评论中来与 without creating a dependency on the framework 一起使用:例如: /*@Nullable*/。这很好,因为您可以注释和检查库或共享代码,但仍然能够在不使用框架的另一个项目中使用该库/共享编码。这是一个很好的功能。我已经习惯使用它,即使我现在倾向于在我的所有项目中启用Checker Framework。

  4. 通过使用存根文件,框架可以使用尚未注释为null的annotate APIs

答案 2 :(得分:52)

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

答案 3 :(得分:32)

根据Java 7 features list JSR-308类型注释被推迟到Java 8.甚至没有提到JSR-305注释。

在最新的JSR-308草案的appendix中有关于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背后的人之一。

答案 4 :(得分:26)

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

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

  

支持库本身也已经注释了这些   注释,所以作为支持库的用户,Android Studio会   已经检查过您的代码并根据这些问题标记潜在问题   注释

答案 5 :(得分:18)

如果有人正在寻找IntelliJ类:您可以使用

从maven存储库中获取它们
<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 

答案 6 :(得分:18)

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

以下是默认情况下如何将@Nonnull应用于所有类,方法和字段。 请参阅https://stackoverflow.com/a/13319541/14731https://stackoverflow.com/a/9256595/14731

  1. 定义@NotNullByDefault
  2. 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
        {
        }
    

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

    @NotNullByDefault
    package com.example.foo;
    

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

      

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

    看起来JSR 308 使其成为JDK 8,虽然JSR没有定义@NotNull,但伴随的Checkers Framework却如此。在撰写本文时,由于此错误,Maven插件无法使用:https://github.com/typetools/checker-framework/issues/183

答案 7 :(得分:12)

Eclipse也有自己的注释。

org.eclipse.jdt.annotation.NonNull

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

答案 8 :(得分:11)

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

答案 9 :(得分:7)

不幸的是,JSR 308不会在此处添加比此项目本地Not Null建议更多的值

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

背后没有任何商业力量,因此JSR 308现在EDR 3启动JCP(早期草案审核),而Java 8应该在不到6个月内发货: -O 与310 btw类似。但与308 Oracle不同的是,现在远离其创始人,以尽量减少对Java平台的伤害。

Checker FrameworkJSR 308背后的每个项目,供应商和学术类都将创建自己的专有检查器注释。

使源代码在未来几年内不兼容,直到可以找到一些受欢迎的妥协,并可能添加到Java 910,或者通过Apache Commons或{{1}等框架}; - )

答案 10 :(得分:7)

的Android

这个答案是针对Android的。 Android有一个名为support-annotations的支持包。这会提供dozens Android specific个注释,并提供NonNullNullablecompile 'com.android.support:support-annotations:23.1.1' 等。

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

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}

然后使用:

cd /${1-$PWD}

答案 11 :(得分:6)

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

对于不应该为null的东西:

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

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

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

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

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

一些注释解释:

  • 使用包javax.validation进行Findbugs / spotbugs / jsr305注释。*与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 class PublicApi {

    /**
     * @param firstname MUST NOT be null
     * @param lastname MUST NOT be null
     */
    public Person createPerson(
            // Spotbugs ignores the param annotations, but IDEs will show problems
            @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);
    }
}

请注意,当取消引用可以为null的方法参数时(参见编写时,Spotbugs版本3.1),无法使Spotbugs发出警告。也许checkerframework可以做到这一点。

答案 12 :(得分:5)

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

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 {}

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

答案 13 :(得分:4)

如果您正在为Android开发,那么有些与Eclipse绑定(编辑:在撰写时,不再是),它有自己的注释。它包含在Eclipse 3.8+(Juno)中,但默认情况下已禁用。

您可以在偏好设置&gt;中启用它。 Java&gt;编译器&gt;错误/警告&gt;空分析(底部的可折叠部分)。

选中“启用基于注释的空分析”

http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage有关于设置的建议。但是,如果您的工作区中有外部项目(如facebook SDK),它们可能无法满足这些建议,您可能不希望在每次SDK更新时修复它们; - )

我用:

  1. 空指针访问:错误
  2. 违反空指定:错误(链接到第#1点)
  3. 潜在的空指针访问:警告(否则facebook SDK会有警告)
  4. 空注释与空推理之间的冲突:警告(链接到第3点)

答案 14 :(得分:4)

如果您正在开展一个大项目,那么最好创建您自己的 @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 
{
}

如果使用正确的retention policy,那么注释将无法在运行时使用。从这个角度来看,它只是一个内部的东西。

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

  • 这是内部的事情。 (无功能或技术影响)
  • 有许多用法。
  • IDE就像IntelliJ支持自定义@Nullable / @NotNull注释一样。
  • 大多数框架也喜欢使用自己的内部版本。

其他问题(见评论):

如何在IntelliJ中配置?

  

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

答案 15 :(得分:3)

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

  1. 通过使用java.util.Optional
  2. 包装可空字段,使类型显式为可空字段
  3. 使用java.util.Objects.requireNonNull
  4. 检查构建时所有非可空字段是否为空

    示例:

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

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

    编辑:我后来发现有些人认为在论证中使用Optional是一种不好的做法,这里有利弊的良好讨论Why should Java 8's Optional not be used in arguments

答案 16 :(得分:2)

现在太阳没有自己的吗?这是什么:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

这似乎与我在过去几年中使用的所有Java版本打包在一起。

编辑:如下面的评论所述,您可能不想使用这些。在这种情况下,我的投票是针对IntelliJ jetbrains注释的!

答案 17 :(得分:2)

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

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>

此批注的主要优点是Spring为使用javax.validation.constraints.NotNull注释的方法参数和类字段提供支持。您需要做的只是启用支持:

  1. 为bean验证提供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>
    
  2. 将SpringValidationPostProcessor提供给spring的上下文

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

  4. 示例:

    @Service
    @Validated
    public class MyServiceImpl implements MyService {
    
      @Override
      public Something doSomething(@NotNull String myParameter) {
            // No need to do something like assert myParameter != null  
      }
    }
    

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

    您还可以验证返回值。

    蜜蜂验证框架javax.validation.constraints.NotNull的另一个重要好处是,目前它仍在开发中,并且计划在新版本2.0中使用新功能。

    @Nullable怎么样?在Beans Validation 1.1中没有类似的东西。好吧,我可以说如果你决定使用@NotNull,那么所有未注明@NonNull的内容都是有效的&#34;可空的&#34;,那么@Nullable注释就没用了。

答案 18 :(得分:1)

另一个选项是随ANTLR 4提供的注释。在Pull Request #434之后,包含@NotNull@Nullable注释的工件包括一个产生编译时错误和/或警告的注释处理器如果其中一个属性被误用(例如,如果两个属性都应用于同一个项目,或者@Nullable应用于具有基本类型的项目)。注释处理器在软件开发过程中提供额外的保证,即应用这些注释所传达的信息是准确的,包括在方法继承的情况下。

答案 19 :(得分:1)

关于IntelliJ的优点之一是您不需要使用它们的注释。您可以编写自己的工具,也可以使用自己喜欢的任何其他工具。您甚至不限于单一类型。如果您正在使用两个使用不同@NotNull批注的库,则可以告诉IntelliJ使用它们两者。为此,请转到“配置检查”,单击“恒定条件和例外”检查,然后单击“配置检查”按钮。我会尽可能使用Nullness Checker,因此我将IntelliJ设置为使用这些注释,但是您可以使其与所需的任何其他工具一起使用。 (我对其他工具没有意见,因为我已经使用IntelliJ多年了,所以我很喜欢。)

答案 20 :(得分:0)

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

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

据我所知,与Kotlin兼容的唯一Nullable软件包是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>

等级:

implementation 'org.jetbrains:annotations-java5:15.0'

答案 21 :(得分:0)

Spring 5在程序包级别具有@NonNullApi。对于已经具有Spring依赖项的项目来说,这似乎是一个方便的选择。所有字段,参数和返回值默认为@NonNull,而@Nullable可以在少数几个不同的地方应用。

文件package-info.java:

@org.springframework.lang.NonNullApi
package com.acme;

https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations