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

1317

我希望让我的代码更易读,并使用工具如IDE代码检查和/或静态代码分析(FindBugs和Sonar)来避免NullPointerException。许多工具似乎与彼此的@NotNull/@NonNull/@Nonnull注释不兼容,在我的代码中列出所有这些注释将非常难以阅读。有哪些推荐的“最佳”注释?以下是我找到的等效注释列表:


258
Apache 应该发明一个“通用”注解,并提供一个工具,可以将其转换为任何其他注解。解决过多标准的问题是发明一个新的标准。 - irreputable
10
如果 Apache 发明了一个新的“通用”工具,可能会有 56 个版本出现,且与其他项目重叠。而且,它也不一定是标准(标准≠普及)。最好使用真正标准的东西,比如 javax?.*。顺便说一下,在这些例子中并没有“太多标准”,我只看到了一个或两个。 - ymajoros
8
javax.annotation.Nonnull 可以与 findbugs 一起使用(我刚测试过),这是我使用它的一个有力理由。 - Nicolas C
26
如果我仅写@NotNull,则指的是com.sun.istack.internal.NotNull。天哪... - Thomas Weller
4
Optionals可以在你以前使用空对象(NullObjects)的情况下非常有用。但它们并没有像运行时的@NotNull注释那样解决相同的问题,而且它们会导致繁琐的解包过程。 - Dave
显示剩余11条评论
25个回答

424

由于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.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))。

就如同这个SO回答所描述的,运行时注解的影响要比想象中小,但是它们带来的好处是除了编译时检查之外能够让工具进行运行时检查。

另一个重要的区别是代码中可以使用注解的位置。有两种不同的方法。一些包使用JLS 9.6.4.1风格的上下文。以下表格给出了一个概述:

Package FIELD METHOD PARAMETER LOCAL_VARIABLE
android.support.annotation ✔️ ✔️ ✔️
edu.umd.cs.findbugs.annotations ✔️ ✔️ ✔️ ✔️
org.jetbrains.annotation ✔️ ✔️ ✔️ ✔️
lombok ✔️ ✔️ ✔️ ✔️
javax.validation.constraints ✔️ ✔️ ✔️

org.eclipse.jdt.annotationjavax.annotationorg.checkerframework.checker.nullness.qual使用JLS 4.11中定义的上下文,我认为这是正确的做法。

这让我们面临着

  • javax.annotation
  • org.checkerframework.checker.nullness.qual

在本轮中。

代码

为了帮助您自行比较更多细节,我列出了每个注释的代码。 为了更容易比较,我删除了注释、导入和@Documented注释。 (除了Android包中的类之外,它们都有@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,所以我将它们单独列出;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 中得到了原生支持。

摘要

我理想的注解应该是使用 java.annotation 语法与 Checker Framework 实现。

如果您不打算使用 Checker Framework,则 javax.annotation (JSR-305) 目前仍然是您最好的选择。

如果您愿意接受 Checker Framework,请使用它们的 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

13
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 - robinst
31
反对使用javax.annotation的另一个观点是,它会在Java 9中引起问题,因为其他模块也提供了该包中的类(jax-ws)。 - robinst
13
Findbugs项目已经停止,其继任者Spotbugs项目正在移除那些注释:https://github.com/spotbugs/spotbugs/pull/180 - robinst
15
JSR 305(https://jcp.org/en/jsr/detail?id=305)本应标准化javax.annotation.NonNull,但由于其规范负责人失踪而未能完成。这与Oracle的任何决定无关。 - Mark Reinhold
13
不使用jsr305.jar的另一个原因是它似乎违反了Oracle Java二进制授权许可协议:https://github.com/google/guava/issues/2960 - Flow
显示剩余8条评论

100

我非常喜欢Checker Framework,它是类型注释(JSR-308)的实现,用于实现缺陷检查器,例如nullness checker。我没有尝试过其他实现来进行比较,但我对这个实现感到满意。

我与提供该软件的团队无关,但我是一个粉丝。

我喜欢这个系统的四个方面:

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

  2. nullness检查的默认设置效果很好:除了本地变量外都是非空(NNEL)。基本上这意味着默认情况下,检查器将所有东西(实例变量、方法参数、泛型类型等)视为默认具有@NonNull类型的。根据文档:

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

    如果NNEL对您不起作用,您可以为类或方法设置不同的默认值。

  3. 这个框架允许您使用注释将注解包裹起来,从而不会创建对该框架的依赖,例如:/*@Nullable*/。 这很好,因为您可以对库或共享代码进行注释和检查,但仍然能够在不使用该框架的另一个项目中使用该库/共享代码。这是一个很好的特性,我已经习惯了使用它,即使现在我 tend to 在所有项目上启用Checker Framework。

  4. 该框架通过使用存根文件的方式注释未被标记为空值的API。


4
看起来不错,我想使用它,但不能。为什么是GPL?不能用LGPL吗? - Burkhard
15
根据常见问题解答: "更为宽松的 MIT 许可证适用于您可能希望包含在自己程序中的代码,例如注释。" - seanf
1
目前链接已损坏。但这个使用Checker Framework的建议值得一加。 - Paul Wagland
1
很遗憾不可变性检查器在最新版本中被删除了。 - Franklin Yu
2
Checker Framework 也被建议在 Oracle Java 教程 中使用。 - Quazi Irfan
似乎只有一个可以正常工作在JDK11和非Android环境下的代码检查工具。我也试过FindBugs(不支持JDK11)、SpotBugs(在JDK11上安装困难)、NullAway(必须使用Errorprone,设置麻烦)、Infer(不支持JSR305/308)。 - addlistener

63

我使用IntelliJ,因为我主要关注IntelliJ标记可能会产生NPE的事情。我同意没有在JDK中使用标准注释是令人沮丧的。有谈论要添加它,它可能会进入Java 7。如果是这样,那么就会有更多的选择!


75
更新:现在IntelliJ支持所有上述注释进行代码高亮,因此您不再受限于IntelliJ的注释。链接:http://blogs.jetbrains.com/idea/2011/03/more-flexible-and-configurable-nullublenotnull-annotations/。 - Daniel Alexiuc
7
javax.annotation.Nonnull 更被广泛认可,不是吗? - Martin
1
但不幸的是,它不使用它们进行其运行时检查,因此仍然使用JetBrains的有益。 - Hakanai
4
自2016年3月起,它为所有这些创建了运行时检查。 - Karol S
1
Java 17... 还在期待中,哈哈哈 - Pwnstar
显示剩余3条评论

33
根据 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 的兴趣重新振作。据我所知,JSR-305 团队尚未正式放弃他们的工作。他们只是安静了两年以上。
有趣的是,Bill Pugh(JSR-305 技术负责人)是 FindBugs 背后的一个人。

4
@pst - 目前的计划是Java 8在2013年9月发布正式版 - http://www.infoq.com/news/2012/04/jdk-8-milestone-release-dates - Stephen C
2
现在已经推迟到了2014年3月 - http://openjdk.java.net/projects/jdk8/. JSR 308包含在M7版本中(请查看“104- Java类型上的注释”)。 - Stephen C

28
对于Android项目,您应该使用android.support.annotation.NonNullandroid.support.annotation.Nullable。这些和其他有用的Android特定注释都在Support Library中提供。
http://tools.android.com/tech-docs/support-annotations中得知:
支持库本身也已用这些注释进行了注释,因此作为支持库的用户,Android Studio将根据这些注释检查您的代码并标记潜在的问题。

3
提供该建议的理由将会很有用。 - apricot
2
支持库本身也已经用这些注释进行了标注,因此作为支持库的用户,Android Studio将已经检查您的代码,并根据这些注释标记潜在问题。 - James Wald
3
顺便提一下,Android Studio 支持使用 javax.annotation.* 注释来支持 jsr305。 - CAMOBAP

24
区分静态分析和运行时分析。将静态分析用于内部内容,将运行时分析用于代码的公共边界。
对于不应为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注释与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之外进行静态检查的两个免费工具:Spotbugs(以前是Findbugs)和checkersframework。
  • Eclipse库有@NonNullByDefault,而jsr305只有@ParametersAreNonnullByDefault。这些只是方便包装器,将基本注释应用于包(或类)中的所有内容,您可以轻松创建自己的包装器。这可以用于包。这可能会与生成的代码(例如lombok)发生冲突。
  • 应避免将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);
    }
}

请注意,目前版本的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值,并在传递null值时返回有用的错误信息。

我现在才发现这个答案,但是@tkruse,你在哪里找到的这个信息:“Eclipse jdt注释不适用于静态方法返回和其他一些情况”?(第一部分不正确,第二部分相当模糊 :))。 - Stephan Herrmann
@StephanHerrmann:我记不清了。我已经删除了这个项目符号。 - tkruse

20

如果有人只是想寻找IntelliJ类:您可以从Maven仓库获取它们,使用以下命令:

<dependency>
    <groupId>com.intellij</groupId>
    <artifactId>openapi</artifactId>
    <version>[desired version]</version>
</dependency>
<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 

这是导致Intellij发出警告的代码。 - Ali
当前版本(截至2017年5月)为15.0。 - BamaPookie
没错。我已经更新了版本。尽管我猜它并没有改变太多。 - Bruno Eberhard
请注意,JetBrains注释在运行时不会保留,因此Guice @Nullable支持无法使用它。 - Peter Major

19

JSR305和FindBugs都是由同一个人编写的。它们都得不到很好的维护,但是它们是标准的,并且被所有主要的IDE支持。好消息是,它们可以直接使用。

以下是如何默认应用@Nonnull到所有类、方法和字段中。

请参考https://dev59.com/N2Yr5IYBdhLWcg3w6OGd#13319541https://dev59.com/vWDVa4cB1Zd3GeqPcltn#9256595
  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://dev59.com/vWDVa4cB1Zd3GeqPcltn#9256595
     */
    @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,但随附的检查器框架确实有。在撰写本文时,由于此错误,Maven插件无法使用:https://github.com/typetools/checker-framework/issues/183


2
Maven 的主要问题已经解决,所以这应该再次成为一个选项。 - Marc von Renteln
我通过Maven使用FindBugs,我的IDE没有做任何事情,这避免了IDE特定的注释,你有什么建议? - Christophe Roussy
@ChristopheRoussy,你的问题是特定于IDE的。请开一个单独的问题。 - Gili

12

看起来这将从Eclipse 3.8(Juno)集成,这将使Eclipse在这方面与IntelliJ保持一致。此外,它应该允许您配置自己的Null注释(例如javax.annotation.Nonnull),并具有将NotNull作为默认选项的选项。 - Motti Strom

12

JSpecify将是未来的趋势(在足够准备好时)。实际上:他们的演示文稿积极地链接到这个问题,并明确表示他们的目标是最终得到一个很好的答案。

它拥有像Android、Guava和Kotlin这样的主要参与者。


1
现在呢?他们的代码库和网站并没有给人可用的印象。似乎 Maven 上有一个 v0.2.0 的版本,但是代码库里面没有任何东西。 - gix
1
您可以使用 org.jspecify:jspecify:0.2.0,它实际上有2个注释。请参阅 https://github.com/jspecify/jspecify/releases/。由于它仍处于测试版阶段,他们强调不要在库中使用它。 - Cristan
同时发布了Meanwhile v0.3.0版本,附带了一份良好的用户指南:https://jspecify.dev/docs/user-guide。对于`@NullMarked`的"pro"功能,IntelliJ IDE的支持还不完全,但将会进行修复:https://youtrack.jetbrains.com/issue/IDEA-323691/JSpecifys-NullMarked-not-considered-for-Not-annotated-method-overrides-method-annotated-with-NotNull-inspection(请投票支持)。 - koppor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接