如何更有效地使用@Nullable和@Nonnull注释?

Mik*_*der 120 java annotations nullable nullpointerexception code-standards

我可以看到@Nullable@Nonnull注释可以在防止有用NullPointerException秒,但他们并不很远传播.

  • 在一个间接层之后,这些注释的有效性完全下降,所以如果你只添加一些注释,它们就不会传播得很远.
  • 由于这些注释没有得到很好的执行,因此存在假设标记的值@Nonnull不为空并因此不执行空检查的危险.

下面的代码会导致标有一个参数@Nonnullnull没有提出任何投诉.它会NullPointerException在运行时抛出.

public class Clazz {
    public static void main(String[] args){
        Clazz clazz = new Clazz();

        // this line raises a complaint with the IDE (IntelliJ 11)
        clazz.directPathToA(null);

        // this line does not
        clazz.indirectPathToA(null); 
    }

    public void indirectPathToA(Integer y){
        directPathToA(y);
    }

    public void directPathToA(@Nonnull Integer x){
        x.toString(); // do stuff to x        
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法使这些注释更严格地执行和/或进一步传播?

Ped*_*hat 57

简短回答:我想这些注释只对您的IDE有用,可以警告您可能出现空指针错误.

正如"清洁代码"一书中所述,您应该检查公共方法的参数,并避免检查不变量.

另一个好的提示是永远不会返回空值,而是使用Null对象模式.

  • 对于可能为空的返回值,我强烈建议使用`Optional`类型而不是plain`null` (7认同)
  • @GauravJ为什么你会直接使用一个可空变量而不检查,如果它先为空?;-) (6认同)
  • 在这种情况下,`Optional` 和 nullable 之间的区别在于 `Optional` 更好地传达了这个值可以有意为空。当然,它不是魔杖,在运行时它可能会以与可为空变量完全相同的方式失败。但是,在我看来,使用`Optional` 程序员接收 API 会更好。 (6认同)
  • 可选的并不比"null"更好.可选#get()抛出NoSuchElementException,而null的使用会抛出NullPointerException.两者都是RuntimeException,没有有意义的描述.我更喜欢可以为空的变量. (4认同)
  • @ 30thh为什么你会直接使用Optional.get()而不是Optional.isPresent()或Optional.map? (2认同)

Uwe*_*nus 26

除了IDE之外,IDE还会提示您null在预期不为空的位置传递提示,您还有其他优势:

  • 静态代码分析工具可以像IDE一样进行测试(例如FindBugs)
  • 您可以使用AOP来检查此断言

因此,它可以帮助创建更易于维护的代码(您不需要null检查)并且更不容易出错.

  • 我在这里同情OP,因为即使你引用这两个优点,在这两种情况下你都使用了"can"这个词.这意味着无法保证这些检查实际发生.现在,这种行为差异对于您希望避免在生产模式下运行的性能敏感测试非常有用,我们已经"断言"了.我发现`@Nullable`和`@Nonnull`是有用的想法,但是我想要更多的力量支持它们,而不是我们假设一个人可以*做什么,这仍然留下了与之无关的可能性他们. (8认同)
  • 问题是从哪里开始.目前他的咒语是可选的.有时我想要它,如果不是因为在某些情况下执行它们会有所帮助...... (2认同)

Ste*_*ann 12

在兼容1.8中编译Eclipse中的原始示例并启用基于注释的null分析,我们收到此警告:

    directPathToA(y);
                  ^
Null type safety (type annotations): The expression of type 'Integer' needs unchecked conversion to conform to '@NonNull Integer'
Run Code Online (Sandbox Code Playgroud)

此警告的措辞类似于使用原始类型("未经检查的转换")将通用代码与旧代码混合时所获得的警告.我们在这里具有完全相同的情况:方法indirectPathToA()具有"遗留"签名,因为它没有指定任何空契约.工具可以很容易地报告这个,所以他们会追逐你所有需要传播但是尚未传播空注释的小巷.

使用聪明人时,@NonNullByDefault我们甚至不必每次都这么说.

换句话说:null注释是否"传播得非常远"可能取决于您使用的工具,以及您如何严格地处理该工具发出的所有警告.使用TYPE_USE null注释,您最终可以选择让工具警告您程序中每个可能的NPE,因为nullness已成为类型系统的一个内在属性.


jon*_*nzh 11

我认为这个原始问题间接指向仍然需要运行时空指针检查的一般建议,即使使用了@NonNull.请参阅以下链接:

Java 8的新Type Annotations

在上面的博客中,建议:

可选类型注释不能替代运行时验证 在类型注释之前,用于描述诸如可空性或范围之类的内容的主要位置在javadoc中.使用Type注释,此通信以编译时验证的方式进入字节码.您的代码仍应执行运行时验证.

  • @swooby 如果我确定我的代码是正确的,通常我会忽略 lint 警告。这些警告不是错误。 (2认同)

小智 7

我同意注释"不会传播得很远".但是,我看到了程序员的错误.

我将Nonnull注释理解为文档.以下方法表示需要(作为前提条件)非空参数x.

    public void directPathToA(@Nonnull Integer x){
        x.toString(); // do stuff to x        
    }
Run Code Online (Sandbox Code Playgroud)

以下代码段包含一个错误.该方法调用时directPathToA()不强制执行y非null(即,它不保证被调用方法的前提条件).一种可能性是添加Nonnull注释indirectPathToA()(传播前提条件).可能性二是检查yin 的无效性indirectPathToA()并避免调用directPathToA()when y为null.

    public void indirectPathToA(Integer y){
        directPathToA(y);
    }
Run Code Online (Sandbox Code Playgroud)

  • @Nonnull 注释只是强调参数的空验证是在你这边(你必须保证你传递非空值)。这不是该方法的责任。 (3认同)

Mik*_*der 6

如果您使用 Kotlin,它会在其编译器中支持这些可空性注释,并会阻止您将空值传递给需要非空参数的 java 方法。虽然这个问题最初是针对 Java 的,但我提到这个 Kotlin 特性是因为它专门针对这些 Java 注释,问题是“有没有办法让这些注释更严格地执行和/或进一步传播?” 而这个特性确实让这些注解得到了更严格的执行

使用@NotNull注解的Java 类

public class MyJavaClazz {
    public void foo(@NotNull String myString) {
        // will result in an NPE if myString is null
        myString.hashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

Kotlin 类调用 Java 类并为用 @NotNull 注释的参数传递 null

class MyKotlinClazz {
    fun foo() {
        MyJavaClazz().foo(null)
    }
}  
Run Code Online (Sandbox Code Playgroud)

强制执行@NotNull注释的Kotlin 编译器错误。

Error:(5, 27) Kotlin: Null can not be a value of a non-null type String
Run Code Online (Sandbox Code Playgroud)

请参阅:http : //kotlinlang.org/docs/reference/java-interop.html#nullability-annotations

  • 该问题针对 Java,根据其第一个标签,而不是 Kotlin。 (3认同)
  • @seh 请参阅更新,了解为什么此答案与此问题相关。 (2认同)
  • 很公平。这是 Kotlin 的一个很好的特性。我只是不认为它会满足那些来这里学习 Java 的人。 (2认同)

TmT*_*ron 5

在我的项目中,我要做的是在“恒定条件与异常”代码检查中激活以下选项:
建议@Nullable批注用于可能返回空值并报告传递给非批注参数的可空值的方法 视察

激活后,所有未注释的参数都将被视为非空值,因此您还将在间接调用中看到警告:

clazz.indirectPathToA(null); 
Run Code Online (Sandbox Code Playgroud)

对于更强大的检查检查框架可能是一个不错的选择(见本不错的教程
:我没用过那又并有可能与杰克编译器的问题:看到这个错误报告