javax.annotation.Nonnull与assert的区别

15

我正在使用Findbugs和javax.annotation.Nonnull来对方法参数进行标注。

对于私有方法,我通常会添加assert语句来检查是否为空值,例如:

private void myMethod(@Nonnull String str) {
    assert str != null
    ....

最新版本的Netbeans(7.3rc2)报告称断言检查不必要(因为有Nonnull注释)。我不确定这是否是Netbeans的错误。

如果我指定了@Nonnull注释,那么可以删除assert行吗?

据我所知,注释仅在静态分析期间使用,而启用时,assert在执行期间处于活动状态,因此两者并不是替代品。


请参考Programmers.SE上的这个相关问题 - David Harkness
lombok.NonNull 会为你添加代码。 - juanmf
4个回答

13

断言(assert)在运行时评估,注解(annotation)可以帮助FindBugs在运行之前进行分析并捕获问题。由于这两个检查并不真正冲突,因此您可以将它们保留。如果我的IDE告诉我要删除assert,我会感到非常烦恼。


不仅是FindBugs,现代IDE(如IntelliJ)也在其分析中使用它。 - Benny Bottema
是的,集成开发环境已经在追赶了,但我也喜欢在构建过程中(在IDE之外)运行它,并在发现严重问题时使构建失败。 - Christophe Roussy

8

Netbeans是正确的。如果你认为可以为空:删除注释。如果你知道它不能为null:删除断言。

如果有任何可能导致方法被带有null值调用的情况,那么@Nonnull注释就不应该存在。

就像你所说的那样,这个注释实际上在运行时并没有起到任何作用:它只被IDE和静态代码分析工具使用,它无法确保事物不是null。


在这个例子中,我假设该参数永远不应该为 null。 - Gualtiero Testa
2
通过添加注释,我告诉Findbugs“被注释的元素不能为空”。Findbugs将检查对该方法的所有调用,以确保参数永远不为空。因此,在这种情况下需要注释。问题是“断言是否有用?”Findbugs在分析中可能会出错,因此断言可以覆盖Findbugs未检测到的动态情况。 - Gualtiero Testa
5
实际上,开发者想要两者兼备。断言会在代码分析未覆盖到的情况下快速失败,而注解则会在开发过程中突出错误。虽然你的回答在理论上是正确的,但我不建议删除任何东西。 - Christian Strempfer
FindBugs确实不是百分之百可靠的,它会尽力寻找问题,但并不总是有效。断言是您运行时的安全保障。 - Christophe Roussy

1

由于这是私有方法,我们可以确保已注释的参数不会为空。我认为你可以删除此断言。

如果NetBeans对公共方法发出警告,则可能存在问题。我建议您放置断言。

如果您仍然觉得私有方法中的断言是必要的,则可以使用字节码注入。 例如,这是一个用于注入空检查的Maven插件。很抱歉这是我的个人项目,但它适合我。我想它可以满足您的需求。 https://github.com/KengoTODA/jsr305-maven-plugin


0

我找到了一种不同的解决方案,因为我在思考我的 IDE 警告。

最初,我觉得 IDE 是错的。我是一个多疑的程序员,希望能够同时拥有文档和静态分析的标签以及运行时检查,以防我从反射、另一个 JVM 语言或一些无法进行静态分析的地方使用它,所以我认为给我一个警告并告诉我 assert(x != null) 语句是不需要的是错误的。

但后来我想到,根据传递给 Java 的 -ea 标志的状态,可以删除断言,而且在某些方面,assert@Nonnull 真的都是开发期间的检查。

事实证明,有一种实际的运行时检查可以插入(Java 7+)Objects.requireNonNull,它会抛出 NullPointerException,并且无法通过 -ea 断言删除。我认为我会更喜欢这个方法而不是我的 assert(x != null); use(x); 模式。

public ConstructorForClass(@Nonnull Type x) {
  this.x = Objects.requireNonNull(x);
  //...
}

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