NonNull注释的作用是什么?

10

我不理解NonNull注释应该如何帮助。假设我有以下代码:

void noNullArg(@NonNull Object o)
{
    // stuff
}

如果我这样做,会收到一个关于'o'可能为null的警告。
void foo()
{
    Object o = null;
    noNullArg(o);
}

但是,如果我这样做,却没有收到任何警告。

void sendNull()
{
    // Pass null and violate the annotation
    foo(null);
}

void foo(Object o)
{
    noNullArg(o);
}

这是一个相当微不足道的情况,无法被检测出来。更糟糕的是,编译器似乎认为如果设置了@NonNull,则检查null是不必要的,但很明显并非如此(它说条件始终为false)。


Java编译器不会检查调用堆栈,它只会检查直接调用者。 - Rahman
1
你所谓的“相当琐碎的情况”需要运行时检查或编译器进行全面的流分析。这根本不是琐碎的问题。 - user207421
1
当然。在传递给noNullArg之前,对象o没有进行空值检查,因此可能会出现警告。他们选择不这样做,但如果我在noNullArg内部检查null,Lint会告诉我这是浪费时间。 - Mark Herscher
1个回答

5
您可能知道,空指针异常是Java中非常常见的故障情况。当编译器看到代码作为第二种情况时,它会显示警告。
由于内在的复杂性,最好将流分析分成小块进行。一次分析一个方法将使性能良好,这样的优点是分析快速,编译器可以在您输入时提醒您。但是,不好的一面是分析无法看到哪些值在方法之间运行(作为参数或返回)。 这就是为什么在第三种情况下不会显示任何警告的原因。正如EJP所说,它将检查运行时。
@NonNull意味着null不是合法的值。
在这里,空注释变得非常重要。通过定义@NonNull注释,您可以告诉编译器,您不想在该位置使用空值。
但是,调用者有责任永远不要传递空值,这需要通过显式的空检查来确保。

好的,这都很有道理。那么为什么 Lint 在我尝试检查 null 时会发出警告呢?它说表达式始终为 false,暗示它永远不可能为 null(当然这是不正确的)。我确定我已经禁用了它,但为什么还会出现明显错误的警告呢? - Mark Herscher
那完全没有回答我的最后一个问题。 - Mark Herscher
4
@NonNull 没有运行时检查。我尝试了一下,即使将 null 作为 @NonNull 参数传入,方法仍会正常执行。所以如果没有运行时检查,为什么 Lint 告诉我在函数内部不需要自己检查 null 呢?实际上并没有保证。我认为注释对于通知使用该方法的人知道可以期待什么非常有价值。 - Mark Herscher
我也想知道这个问题的答案。 - worked
1
我认为通过使用NonNull标记方法参数,您承诺您的方法不支持指定参数的null值,因此添加任何null检查都没有意义。如果您想处理null值并使方法“null友好”,只需删除NonNull即可。 - Eldar Budagov
通常情况下,我在使用注释更新旧代码时会检查空值,并且对于新代码则不进行空值检查。所有额外的检查都会大幅增加所需的单元测试数量以实现适当的测试覆盖率。 - G_V

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