我应该使用哪个@NotNullJava注释?

我希望使我的代码更具可读性,并使用IDE代码检查和/或静态代码分析(FindBugs和Sonar)等工具来避免NullPointerExceptions。许多工具似乎与其他工具的@NotNull/@NonNull/@Nonnull注释不兼容,并且在我的代码中列出所有这些注释可能很难阅读。关于哪个是“最佳”的任何建议?这是我找到的等效注释列表:

379042 次浏览

在最新的JSR-308草案的中有一些关于JSR-305状态的信息。这包括JSR-305注释似乎被遗弃的观察。JSR-305页面也将其显示为“非活动”。

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


事实上,JSR-308没有定义任何注释类型/类,看起来他们认为它超出了范围。(考虑到JSR-305的存在,他们是对的)。

然而,如果JSR-308真的看起来像是Java8,那么如果对JSR-305的兴趣恢复,我也不会感到惊讶。AFAIK,JSR-305团队并没有正式放弃他们的工作。他们只是安静了两年多。

有趣的是,Bill Pugh(JSR-305的技术负责人)是FindBugs背后的人之一。

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

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

编辑:正如下面的评论中提到的,您可能不想使用这些。在这种情况下,我投票支持IntelliJ jetBrain注释!

我非常喜欢Checker框架,它是类型注释(JSR-308)的实现,用于像空值检查器一样实现缺陷检查器。我没有真正尝试过任何其他人提供任何比较,但我对这个实现很满意。

我不隶属于提供该软件的组织,但我是一个粉丝。

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

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

  2. 空值检查的默认设置运行良好:除了本地变量(NNEL)之外的非空。基本上这意味着默认情况下,检查器会将除本地变量之外的所有内容(实例变量、方法参数、泛型类型等)视为默认情况下具有@NonNull类型。根据留档:

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

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

  3. 这个框架允许你使用而不会创建对框架的依赖通过将注释包含在注释中:例如/*@Nullable*/。这很好,因为你可以注释和检查库或共享代码,但仍然可以在另一个不使用该框架的项目中使用该库/共享编码。这是一个很好的功能。我已经习惯使用它了,尽管我现在倾向于在我所有的项目上启用Checker框架。

  4. 该框架有一种方法来注释API你使用尚未注释为空通过使用存根文件。

在等待上游(Java8?)的分类时,您也可以定义自己的项目本地@NotNull@Nullable注释。这在您使用JavaSE时也很有用,默认情况下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 {}

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

只是指出Java验证API(javax.validation.constraints.*)没有@Nullable注释,这在静态分析上下文中非常有价值。这对运行时bean验证是有意义的,因为这是Java中任何非原始字段的默认值(即没有要验证/执行的内容)。出于所述目的,应该权衡替代方案。

Eclipse也有自己的注释。

org.eclipse.jdt.annotation.NonNull

详情见http://wiki.eclipse.org/JDT_Core/Null_Analysis

JSR305和FindBugs是由同一个人编写的。两者的维护都很差,但都很标准,并且得到了所有主要IDE的支持。好消息是它们工作得很好。

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

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

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

@NotNullByDefaultpackage com.example.foo;

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

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

它看起来像JSR 308进入JDK 8,尽管JSR没有定义@NotNull,但附带的Checkers Framework定义了。在撰写本文时,由于bug,Maven插件无法使用:https://github.com/typetools/checker-framework/issues/183

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

Java 8不会附带一个默认注释或它自己的Checker框架。与Find-bugs或JSR 305类似,这个JSR由一小群主要是学术团队维护得很差。

它背后没有商业力量,因此JSR 308现在推出EDR 3JCP的早期草案审查),而Java 8应该在不到6个月的时间内发货:-O与310 btw类似,但与308 Oracle不同,它现在已经从其创始人那里负责,以尽量减少对Java平台的伤害。

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

使源代码在未来几年不兼容,直到可以找到一些流行的妥协,并可能添加到Java 910,或通过Apache CommonsGoogle Guava等框架;-)

如果您正在为android开发,您将有点绑定到Eclipse(编辑:在撰写本文时,不再),它有自己的注释。它包含在Eclipse 3.8+(Juno)中,但默认禁用。

您可以在首选项>Java>编译器>错误/警告>空分析(底部的可折叠部分)中启用它。

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

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

我使用:

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

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

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

<dependency><groupId>org.jetbrains</groupId><artifactId>annotations</artifactId><version>15.0</version></dependency>

对于Android项目,您应该使用android.support.annotation.NonNullandroid.support.annotation.Nullable。这些和其他有用的Android特定注释在支持库中可用。

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

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

android

这个答案是Android特定的。Android有名为support-annotations的支持包。这提供了Android特定注释中的几十,还提供了常见的,如NonNullNullable等。

要添加标注支持包,请在build.gradle中添加以下依赖项:

compile 'com.android.support:support-annotations:23.1.1'

然后使用:

import android.support.annotation.NonNull;
void foobar(@NonNull Foo bar) {}

还有另一种方法可以在Java8中做到这一点。我做了两件事情来完成我需要的:

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

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

编辑:我后来发现,有些人认为在参数中使用Optional是一种不好的做法,这里有一个很好的讨论,其中有优点和缺点为什么在参数中不应该使用Java8的可选

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

public class Role {      
// Required fields, will not be null (unless using reflection)private final UUID guid;private final String domain;private final String name;// Optional field, not null but can be emptyprivate final Optional<String> description;
//Non null descriptionpublic 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 nullrequireNonNull(description);
// but wrapped with an Optionalthis.description = Optional.of(description);}
// Null description is assigned to Optional.emptypublic Role(UUID guid, String domain, String name) {this.guid = requireNonNull(guid);this.domain = requireNonNull(domain);this.name = requireNonNull(name);this.description = Optional.empty();}//Note that this accessor is not a getter.//I decided not to use the "get" suffix to distinguish from "normal" getterspublic Optional<String> description(){ return description;}}

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

对于不应该为空的东西:

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

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

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

这应该会给出最好的结果:IDE中的警告、Findbugs和CheckerFramework的错误、有意义的运行时异常。

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

一些注释解释:

  • 带有包javax.validation.*的Findbugs/Splbugs/jsr305注释与Java9+中的其他模块发生冲突,也可能违反Oracle许可证
  • Spotbugs注释在编译时仍然依赖于jsr305/findbugs注释(在编写https://github.com/spotbugs/spotbugs/issues/421时)
  • jetBrain@NotNull名称与@javax.validation.NotNull冲突。
  • 用于静态检查的JetBrain,Eclipse或Checker框架注释具有优于javax.annotations的优势,它们不会与Java9及更高版本中的其他模块发生冲突
  • @javax.annotations.对Findbugs/Spotbugs来说,Nullable并不意味着你(或你的IDE)认为它的意思。Findbugs会忽略它(对成员)。可悲的是,但这是真的(https://sourceforge.net/p/findbugs/bugs/1181
  • 对于IDE之外的静态检查,有两个免费工具:Spotbugs(以前的Findbugs)和CheckersFramework。
  • Eclipse库有@NonNullByDefault,jsr305只有@ParametersArea NonnullByDefault。这些只是方便的包装器,将基注释应用于包(或类)中的所有内容,您可以轻松创建自己的注释。这可以在包上使用。这可能与生成的代码(例如lombok)冲突。
  • 对于与他人共享的库,应避免使用lombok作为导出依赖项,传递依赖越少越好
  • 使用Bean验证框架功能强大,但需要很高的开销,因此仅仅为了避免手动空值检查就太过分了。
  • 对字段和方法参数使用可选是有争议的(您可以轻松找到有关它的文章)
  • Android空注释是Android支持库的一部分,它们附带了很多其他类,并且不能很好地与其他注释/工具一起使用

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

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

// file: PublicApipackage example;
public interface PublicApi {
Person createPerson(// NonNull by default due to package-info.java aboveString firstname,String lastname);}
// file: PublicApiImplpublic 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 nullprivate Person doCreatePerson(String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefaultString 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 itprivate Person getNickname(String firstname,String lastname) {return NICKNAMES.get(firstname + ':' + lastname);}}

请注意,当可空方法参数被取消引用时(在撰写本文时,Spotbugs的3.1版),没有办法让Spotbugs发出警告。

遗憾的是,这些注释没有区分具有任意调用站点的库的公共方法和可以知道每个调用站点的非公共方法的情况。因此,“表明不需要null,但为null被传递做好准备”的双重含义在单个声明中是不可能的,因此上面的示例对接口和实现有不同的注释。

对于拆分接口方法不实用的情况,以下方法是一种折衷方案:

        public Person createPerson(@NonNull String firstname,@NonNull String lastname) {// even though parameters annotated as NonNull, library clients might call with null.if (firstname == null) throw new IllagalArgumentException(...);if (lastname == null) throw new IllagalArgumentException(...);return doCreatePerson(fistname, lastname, nickname);}

这有助于客户端不传递null(编写正确的代码),同时在传递时返回有用的错误。

如果您正在处理一个大项目,您可能更好地创建自己@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{}

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

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

  • 这是一个内部的东西(没有功能或技术影响)。
  • 有许多许多用法。
  • 与IntelliJ类似的IDE支持自定义@Nullable/@NotNull注释。
  • 大多数框架也喜欢使用自己的内部版本。

其他问题(见评论):

如何在IntelliJ中配置它?

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

由于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.constraintsjavax.annotation。前者是JEE附带的,如果它比javax.annotation更好,那么JSE最终可能会出现,或者根本不会出现,这是一个有争议的问题。我个人更喜欢javax.annotation,因为我不喜欢JEE依赖。

这给我们留下了

javax.annotation

这也是最短的一个。

只有一种语法会更好:java.annotation.Nullable。随着其他包的毕业从javaxjava在过去,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))。

这个SO答案中所述,运行时注释的影响比人们想象的要小,但他们有好处使工具能够执行运行时检查,除了编译一次。

另一个重要的区别是可以使用注释的代码中的在哪里。有两种不同的方法。一些包使用JLS9.6.4.1样式上下文。下表给出了概述:

FIELD方法参数LOCAL_VARIABLE
android.support.annotation✔️✔️✔️
edu.umd.cs.findbugs.annotations✔️✔️✔️✔️
org.jetbrains.annotation✔️✔️✔️✔️
龙目岛✔️✔️✔️

我重新排序了行和@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框架,那么#0JSR-305)仍然是您目前最好的选择。

如果您愿意购买Checker框架,请使用org.checkerframework.checker.nullness.qual.


来源

  • android.support.annotationandroid-5.1.1_r1.jar
  • edu.umd.cs.findbugs.annotationsfindbugs-annotations-1.0.0.jar
  • org.eclipse.jdt.annotationorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
  • org.jetbrains.annotationsjetbrains-annotations-13.0.jar
  • javax.annotationgwt-dev-2.5.1-sources.jar
  • org.checkerframework.checker.nullness.qualchecker-framework-2.1.9.zip
  • lombok fromlombok提交f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
  • javax.validation.constraintsvalidation-api-1.0.0.GA-sources.jar

如果您正在使用Spring Framework构建您的应用程序,我建议使用javax.validation.constraints.NotNullBeans验证 打包在以下依赖项中:

    <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. provide MethodValidationPostProcessor to spring's context

      @Configuration@ValidationConfigpublic class ValidationConfig implements MyService {
    @Beanpublic MethodValidationPostProcessor providePostProcessor() {return new MethodValidationPostProcessor()}}
  3. finally you annotate your classes with Spring's org.springframework.validation.annotation.Validated and validation will be automatically handled by Spring.

Example:

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

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

您还可以验证返回值。

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

那么@Nullable呢?在Beans验证1.1中没有这样的东西。好吧,我可以争辩说,如果你决定使用@NotNull,那么所有没有用@NonNull注释的东西实际上都是“可空的”,所以@Nullable注释是无用的。

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

这里已经有太多的答案了,但是(a)现在是2019年,仍然没有“标准”Nullable和(b)没有其他答案引用静态编程语言。

对静态编程语言的引用很重要,因为静态编程语言可以与Java100%互操作,并且它具有核心的空安全功能。当调用Java库时,它可以利用这些注释让静态编程语言工具知道JavaAPI是否可以接受或返回null

据我所知,与静态编程语言兼容的Nullable包只有org.jetbrains.annotationsandroid.support.annotation(现在是androidx.annotation)。后者仅与Android兼容,因此不能用于非Android JVM/Java/静态编程语言项目。然而,JetBrains包适用于任何地方。

因此,如果您开发的Java包也应该适用于Android和静态编程语言(并且受到Android Studio和IntelliJ的支持),那么您的最佳选择可能是JetBrains包。

Maven:

<dependency><groupId>org.jetbrains</groupId><artifactId>annotations-java5</artifactId><version>15.0</version></dependency>

Gradle:

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

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

文件package-info.java:

@org.springframework.lang.NonNullApipackage com.acme;

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

JSpecify将是一条路(当它足够准备好的时候)。事实上:其介绍主动链接到这个问题,并指定他们的目标是最终得到一个好的答案。

它拥有Android,Guava和静态编程语言等主要参与者。

较新的项目可能应该使用jakarta.annotation-apijakarta.annotation包)。
它从现在只读javax.annotation回购链接,并适合新的雅加达生态系统,旨在将社区从所有javax相关的头痛中解放出来。

如果您使用的是Spring 5. x/SpringBoot 2. x,您绝对应该使用Spring注释(org.springframework.lang),因为它们为您提供了带有注释@NonNullFields@NonNullApi的默认包范围的空检查。您甚至不会与其他依赖项中的其他NotNull/NonNull注释发生冲突,因为您使用的是@NonNullFields/@NonNullApi。注释必须在名为package-info.java的文件中使用,该文件位于包的根目录中:

@NonNullFields@NonNullApipackage org.company.test;

要从空值检查中排除某些字段、参数或返回值,只需显式使用@Nullable注释。除了使用@NonNullFields/@NonNullApi,您还可以在任何地方设置@NonNull,但可能最好默认使用@NonNullFields/@NonNullApi激活空值检查,并且只对@Nullable执行特定异常。

IDE(Intellij)将突出显示违反空值条件的代码。如果设置正确,每个开发人员都可以假设字段、参数和返回值不得为空,除非有@Nullable注释。有关更多信息,请查看此文章