提问人:jaxzin 提问时间:2/11/2011 最后编辑:Adam Burleyjaxzin 更新时间:10/12/2023 访问量:410779
我应该使用哪种@NotNull Java 注解?
Which @NotNull Java annotation should I use?
问:
我希望使我的代码更具可读性,并使用 IDE 代码检查和/或静态代码分析(FindBugs 和 Sonar)等工具来避免 NullPointerExceptions。许多工具似乎彼此不兼容 // 注释,在我的代码中列出所有这些工具会很糟糕。关于哪一个是“最好的”的任何建议?以下是我找到的等效注释列表:@NotNull
@NonNull
@Nonnull
javax.validation.constraints.NotNull
为运行时验证而创建,而不是静态分析。
文档edu.umd.cs.findbugs.annotations.NonNull
由 FindBugs(死项目)及其后继者 SpotBugs 静态分析使用,因此 Sonar(现在的 Sonarqube)
FindBugs 文档、SpotBugs 文档javax.annotation.Nonnull
这可能也适用于 FindBugs,但 JSR-305 处于非活动状态。(另请参阅:JSR 305 的状态如何? 源org.jetbrains.annotations.NotNull
IntelliJ IDEA IDE 用于静态分析。
文档龙目岛。NonNull
用于控制 Project Lombok 中的代码生成。
占位符注释,因为没有标准。
来源、文档androidx.annotation.NonNull
Android 中提供的标记注释,由注释包
文档提供org.eclipse.jdt.annotation.NonNull
Eclipse 用于静态代码分析
文档
答:
我使用 IntelliJ 的,因为我最关心的是 IntelliJ 标记可能产生 NPE 的东西。我同意在 JDK 中没有标准注释是令人沮丧的。有人说要添加它,它可能会进入 Java 7。在这种情况下,还会有一个可供选择!
评论
javax.annotation.Nonnull
被更广泛地接受,不是吗?
根据 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 的幕后推手之一。
评论
太阳现在不是有自己的吗?这是什么:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
这似乎与我在过去几年中使用的所有 Java 版本打包在一起。
编辑:如下面的评论中所述,您可能不想使用这些。在这种情况下,我投票给 IntelliJ jetbrains 注解!
评论
我非常喜欢 Checker Framework,它是类型注释 (JSR-308) 的实现,用于实现缺陷检查器,如空值检查器。我还没有真正尝试过任何其他方法来提供任何比较,但我对这种实现感到满意。
我不隶属于提供该软件的团体,但我是粉丝。
我喜欢这个系统的四点:
它有一个用于空 (@Nullable) 的缺陷检查器,但也有用于不可变性和 interning(以及其他)的缺陷检查器。我使用第一个(nullness),我正在尝试使用第二个(不可变性/IGJ)。我正在尝试第三个,但我不确定是否要长期使用它。我还不相信其他检查器的一般有用性,但很高兴知道框架本身是一个用于实现各种附加注释和检查器的系统。
空值检查的默认设置效果很好:非空值,局部变量 (NNEL) 除外。基本上,这意味着默认情况下,检查器将除局部变量之外的所有变量(实例变量、方法参数、泛型类型等)视为默认具有@NonNull类型。根据文档:
NNEL 默认值导致代码中显式批注的数目最少。
如果 NNEL 不适合您,您可以为类或方法设置不同的默认值。
该框架允许您在不创建对框架的依赖的情况下使用,方法是将注释包含在注释中:例如.这很好,因为您可以注释和检查库或共享代码,但仍然能够在另一个不使用框架的项目中使用该库/共享编码。这是一个很好的功能。我已经习惯了使用它,尽管我现在倾向于在我的所有项目上启用 Checker 框架。
/*@Nullable*/
该框架有一种方法可以通过使用存根文件来注释你使用的 API,这些 API 尚未注释为空。
评论
在等待上游(Java 8?)整理出来时,你也可以定义你自己的项目本地和注解。如果您使用的是 Java SE,这在默认情况下不可用时也很有用。@NotNull
@Nullable
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 () 没有附带注释,这在静态分析上下文中非常有价值。这对于运行时 Bean 验证是有意义的,因为这是 Java 中任何非原始字段的默认值(即无需验证/强制执行)。出于所述目的,应权衡替代方案。javax.validation.constraints.*
@Nullable
Eclipse 也有自己的注解。
org.eclipse.jdt.annotation.NonNull
有关详细信息,请参见 http://wiki.eclipse.org/JDT_Core/Null_Analysis。
评论
JSR305 和 FindBugs 是由同一个人编写的。两者的维护都很差,但都是标准的,并且得到了所有主要IDE的支持。好消息是它们按原样运行良好。
以下是默认情况下将@Nonnull应用于所有类、方法和字段的方法。 请参阅 https://stackoverflow.com/a/13319541/14731 和 https://stackoverflow.com/a/9256595/14731
- 定义
@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
@NotNullByDefault
package com.example.foo;
更新:截至 2012 年 12 月 12 日,JSR 305 被列为“休眠”。根据文档:
被执行委员会投票选为“休眠”的 JSR,或者已达到其自然生命周期的 JSR。
看起来 JSR 308 正在进入 JDK 8,尽管 JSR 没有定义@NotNull,但随附的 JSR 定义了。在撰写本文时,由于以下错误,Maven 插件无法使用:https://github.com/typetools/checker-framework/issues/183Checkers Framework
评论
不幸的是,不会添加比这个项目更多的值 本地 不为空 建议在这里JSR 308
Java 8
不会带有单个默认注释或自己的框架。
与 Find-bugs or 类似,这个 JSR 由一小群主要是学术团队维护得很差。Checker
JSR 305
它背后没有商业力量,因此现在推出(早期草案审查),而应该在不到 6 个月的时间内发货:-O
类似于顺便说一句。但与此不同的是,它现在已经远离了它的创始人,以尽量减少它对 Java 平台造成的伤害。JSR 308
EDR 3
JCP
Java 8
310
308 Oracle
每个项目、供应商和学术类都像背后的项目、供应商和学术类一样,将创建自己的专有检查器注释。Checker Framework
JSR 308
使源代码在未来几年内不兼容,直到找到一些流行的折衷方案,并可能添加到 或 中,或者通过 或 等框架Java 9
10
Apache Commons
Google Guava
;-)
如果你正在为 android 开发,那么你在某种程度上与 Eclipse 联系在一起(编辑:在撰写本文时,不再是了),它有自己的注解。它包含在 Eclipse 3.8+ (Juno) 中,但默认情况下处于禁用状态。
您可以在 Java > Compiler > Errors/Warnings > Null 分析(底部的可折叠部分)> Preferences 中启用它。
选中“启用基于注释的空分析”
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage 有关于设置的建议。但是,如果您的工作区中有外部项目(如 facebook SDK),它们可能不满足这些建议,并且您可能不希望在每次 SDK 更新时修复它们;
我使用:
- 空指针访问:错误
- 违反 null 规范:错误(链接到点 #1)
- 潜在的空指针访问:警告(否则 facebook SDK 将出现警告)
- 空注释和空推理之间的冲突:警告(链接到点 #3)
评论
@chaqke
另一个选项是 ANTLR 4 提供的注释。在拉取请求 #434 之后,包含 和 注释的工件包括一个注释处理器,如果其中一个属性被误用(例如,如果两者都应用于同一项,或者如果应用于具有基元类型的项),则会产生编译时错误和/或警告。注释处理器在软件开发过程中提供了额外的保证,即应用这些注释所传达的信息是准确的,包括在方法继承的情况下。@NotNull
@Nullable
@Nullable
如果有人只是在寻找 IntelliJ 类:您可以从 maven 存储库中获取它们
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>15.0</version>
</dependency>
评论
对于 Android 项目,您应该使用 和 .支持库中提供了这些和其他有用的 Android 特定注释。android.support.annotation.NonNull
android.support.annotation.Nullable
从 http://tools.android.com/tech-docs/support-annotations:
支持库本身也用这些注释 注解,因此作为支持库的用户,Android Studio 将 已经检查您的代码并根据这些标记潜在问题 附注。
评论
javax.annotation.*
人造人
这个答案是特定于 Android 的。Android 有一个名为 的支持包。这提供了数十种特定于 Android 的注释,也提供了常见的注释,例如 等。support-annotations
NonNull
Nullable
如需添加 support-annotations 软件包,请在 build.gradle 中添加以下依赖项:
compile 'com.android.support:support-annotations:23.1.1'
然后使用:
import android.support.annotation.NonNull;
void foobar(@NonNull Foo bar) {}
在 Java 8 中还有另一种方法可以做到这一点。 我正在做两件事来完成我需要的事情:
- 通过将可为 null 的字段包装起来,使可为 null 的字段显式使用类型
java.util.Optional
- 检查所有不可为空的字段在构造时是否为空
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 时甚至需要注释吗?
编辑:我后来发现,有些人认为在参数中使用是一种不好的做法,这里有一个很好的讨论,有利弊 为什么 Java 8 的可选不应该在参数中使用Optional
推荐的选项,因为在参数中使用 Optional 不是最佳实践,我们需要 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 empty
private final Optional<String> description;
//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();
}
//Note that this accessor is not a getter.
//I decided not to use the "get" suffix to distinguish from "normal" getters
public Optional<String> description(){ return description;}
}
评论
new Role(null,null,null,null);
description
区分静态分析和运行时分析。对内部内容使用静态分析,对代码的公共边界使用运行时分析。
对于不应为 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 或 checkers用于静态检查的框架注解比 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)冲突。
- 对于与其他人共享的库,应避免使用 lombok 作为导出的依赖项,传递依赖项越少越好
- 使用 Bean 验证框架功能强大,但需要很高的开销,因此只是为了避免手动 null 检查而大材小用。
- 对字段和方法参数使用 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);
}
}
请注意,当取消引用可为 null 的方法参数时,无法使 Spotbugs 发出警告(在撰写本文时,Spotbugs 的 3.1 版)。也许 checkerframework 可以做到这一点。
可悲的是,这些注释没有区分具有任意调用站点的库的公共方法和可以知道每个调用站点的非公共方法的情况。因此,在单个声明中不可能出现双重含义:“指示 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
{
}
如果使用正确的保留策略,则批注在运行时将不可用。从这个角度来看,这只是一个内部的事情。
尽管这不是一门严格的科学,但我认为使用内部类是最有意义的。
- 这是内部的事情。(无功能或技术影响)
- 有很多很多的用法。
- IDE 和 IntelliJ 一样支持自定义/注释。
@Nullable
@NotNull
- 大多数框架也更喜欢使用自己的内部版本。
其他问题(见评论):
如何在 IntelliJ 中配置它?
评论
idea
void test(@NonNull String s) {}
test(null);
由于 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
这给我们留下了 or .
前者带有 JEE。如果这比 更好,最终可能会与 JSE 一起出现,或者根本不会出现,这是一个有争议的问题。
我个人更喜欢,因为我不喜欢 JEE 依赖项。javax.validation.constraints
javax.annotation
javax.annotation
javax.annotation
这给我们留下了
javax.annotation
这也是最短的一个。
只有一种语法会更好:.随着其他包裹的毕业
从过去到 javax.annotation 将
朝着正确的方向迈出一步。java.annotation.Nullable
javax
java
实现
我希望它们都有基本相同的琐碎实现, 但详细的分析表明,事实并非如此。
首先是相似之处:
注释都有行@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 答案中所述,运行时注释的影响 比人们想象的要小,但它们有好处 除了 编译时。
另一个重要的区别是可以在代码中使用注释的位置。 有两种不同的方法。某些软件包使用 JLS 9.6.4.1 样式上下文。下表给出了概述:
包 | 田 | 方法 | 参数 | LOCAL_VARIABLE |
---|---|---|---|---|
android.support.annotation (安注) | ✔️ | ✔️ | ✔️ | |
edu.umd.cs.findbugs.annotations | ✔️ | ✔️ | ✔️ | ✔️ |
org.jetbrains.注解 | ✔️ | ✔️ | ✔️ | ✔️ |
龙目岛 | ✔️ | ✔️ | ✔️ | ✔️ |
javax.validation.constraints | ✔️ | ✔️ | ✔️ |
org.eclipse.jdt.annotation
,并使用 JLS 4.11 中定义的上下文,在我看来,这是正确的方法。javax.annotation
org.checkerframework.checker.nullness.qual
这给我们留下了
javax.annotation
org.checkerframework.checker.nullness.qual
在这一轮中。
法典
为了帮助您自己比较更多细节,我在下面列出了每个注释的代码。
为了便于比较,我删除了注释、导入和注释。
(除了 Android 包中的类外,它们都有)。
我重新排序了行和字段,并规范了资格。@Documented
@Documented
@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
@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();
}
}
支持
根据我的经验,至少 Eclipse 和开箱即用的 Checker Framework 支持。javax.annotation
总结
我理想的注解是 Checker Framework 实现的语法。java.annotation
如果您不打算使用 Checker 框架,javax.annotation
(JSR-305) 仍然是您目前最好的选择。
如果您愿意购买 Checker 框架,只需使用
他们。org.checkerframework.checker.nullness.qual
来源
android.support.annotation
从android-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
从findbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
从org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
从jetbrains-annotations-13.0.jar
javax.annotation
从gwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
从checker-framework-2.1.9.zip
lombok
从 提交lombok
f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
从validation-api-1.0.0.GA-sources.jar
评论
javax.annotation
javax.annotation
javax.annotation.NonNull
如果您使用 Spring Framework 构建应用程序,我建议使用打包在以下依赖项中的来自 Beans 验证:javax.validation.constraints.NotNull
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
这个注解的主要优点是 Spring 同时支持方法参数和用 注解的类字段。要启用支持,您需要做的就是:javax.validation.constraints.NotNull
提供用于 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>
将 MethodValidationPostProcessor 提供给 spring 的上下文
@Configuration @ValidationConfig public class ValidationConfig implements MyService { @Bean public MethodValidationPostProcessor providePostProcessor() { return new MethodValidationPostProcessor() } }
最后,你用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
}
}
当您尝试调用方法 doSomething 并将 null 作为参数值传递时,spring(通过 HibernateValidator)将抛出 .这里不需要手动工作。ConstraintViolationException
还可以验证返回值。
Beans Validation Framework 的另一个重要好处是,目前它仍在开发中,并且计划为新版本 2.0 提供新功能。javax.validation.constraints.NotNull
怎么样?在 Beans Validation 1.1 中没有类似的东西。好吧,我可以争辩说,如果您决定使用所有未注释的内容,那么所有未注释的内容实际上都是“可空的”,因此注释是无用的。@Nullable
@NotNull
@NonNull
@Nullable
评论
IntelliJ 的一个好处是你不需要使用它们的注释。您可以编写自己的工具,也可以使用您喜欢的任何其他工具。您甚至不仅限于单一类型。如果您使用两个使用不同注解的库,您可以告诉 IntelliJ 同时使用它们。为此,请转到“配置检查”,单击“恒定条件和异常”检查,然后点击“配置检查”按钮。我尽可能地使用 Nullness Checker,所以我将 IntelliJ 设置为使用这些注释,但您可以让它与您想要的任何其他工具一起使用。(我对其他工具没有意见,因为我多年来一直在使用 IntelliJ 的检查,我喜欢它们。@NotNull
这里已经有太多的答案了,但是(a)现在是2019年,仍然没有“标准”,(b)没有其他答案参考Kotlin。Nullable
对 Kotlin 的引用很重要,因为 Kotlin 与 Java 是 100% 可互操作的,并且它具有核心的 Null Safety 功能。在调用 Java 库时,它可以利用这些注释让 Kotlin 工具知道 Java API 是否可以接受或返回 。null
据我所知,唯一与 Kotlin 兼容的软件包是 和 (现在 )。后者仅与 Android 兼容,因此不能在非 Android JVM/Java/Kotlin 项目中使用。但是,JetBrains 软件包在任何地方都适用。Nullable
org.jetbrains.annotations
android.support.annotation
androidx.annotation
因此,如果您开发的 Java 包也应该可以在 Android 和 Kotlin 中运行(并且受 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'
评论
javax.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
lombok.NonNull
org.checkerframework
io.reactivex.annotations
Spring 5 在包级别进行了@NonNullApi。对于已经有 Spring 依赖项的项目来说,这似乎是一个方便的选择。所有字段、参数和返回值都默认为 @NonNull,并且可以在几个不同的地方应用@Nullable。
文件包-info.java:
@org.springframework.lang.NonNullApi
package com.acme;
JSpecify 将是要走的路(当它准备好时)。事实上:他们的演讲积极地链接到这个问题,并指出他们的目标是让它最终得到一个好的答案。
它有 Android、Guava 和 Kotlin 等主要参与者。
评论
org.jspecify:jspecify:0.2.0
@NullMarked
较新的项目可能应该使用 jakarta.annotation-api(包)。
它与现在只读的javax.annotation存储库链接,并适合新的jakarta生态系统,该生态系统旨在将社区从所有相关的头痛中解放出来。jakarta.annotation
javax
评论
jakarta.annotation.Nonnull
jakarta.annotation.Nullable
如果您使用的是 Spring 5.x / SpringBoot 2.x,您绝对应该使用 Spring 注解 (org.springframework.lang),因为它们为您提供了默认的包范围的 null 检查,其中包含注解和 .您甚至不会与其他依赖项的其他注释发生冲突,因为您正在使用 .注释必须在名为 package-info.java 的文件中使用,该文件位于包的根目录中:@NonNullFields
@NonNullApi
NotNull/NonNull
@NonNullFields/@NonNullApi
@NonNullFields
@NonNullApi
package org.company.test;
若要从 null 检查中排除某些字段、参数或返回值,只需显式使用注释即可。除了使用之外,您还可以在任何地方设置,但最好在默认情况下激活空检查,并且只使用 .@Nullable
@NonNullFields/@NonNullApi
@NonNull
@NonNullFields/@NonNullApi
@Nullable
IDE (Intellij) 将突出显示违反 null 条件的代码。如果设置正确,每个开发人员都可以假定字段、参数和返回值必须不为 null,除非有注释。有关详细信息,请查看此文章。@Nullable
评论
com.sun.istack.internal.NotNull