Java @具有不同IDE的非空-警告不必要的空检查

Java @具有不同IDE的非空-警告不必要的空检查,java,intellij-idea,findbugs,jsr305,Java,Intellij Idea,Findbugs,Jsr305,我在一个开发人员使用不同IDE的环境中工作——Eclipse、Netbeans和IntelliJ。我使用@Nonnull注释(javax.annotation.Nonnull)来表示方法永远不会返回null: @Nonnull public List<Bar> getBars() { return bars; // this.bars is a final, initialized list } 如果您选择遵循此警告并删除空检查,那么您似乎同样依赖于getBars()实现,而

我在一个开发人员使用不同IDE的环境中工作——Eclipse、Netbeans和IntelliJ。我使用@Nonnull注释(javax.annotation.Nonnull)来表示方法永远不会返回null:

@Nonnull
public List<Bar> getBars() {
  return bars;  // this.bars is a final, initialized list
}
如果您选择遵循此警告并删除空检查,那么您似乎同样依赖于getBars()实现,而不是更改。然而,在这种情况下,您似乎依赖于实现细节,而不是显式契约(如@Nonnull)

编辑#2:

我不关心执行速度,空检查确实非常快。我关心代码的可读性。考虑以下事项:

备选方案A:

if ((foo.getBars() == null || foo.getBars().size() < MAXIMUM_BARS) && 
    (baz.getFoos() == null || baz.getFoos().size() < MAXIMUM_FOOS)) { 
  // do something
}
if((foo.getbar()==null | | | foo.getbar().size()
备选案文B:

if (foo.getBars().size() < MAXIMUM_BARS && 
    baz.getFoos().size() < MAXIMUM_FOOS) {
  // do something
}
if(foo.getbar().size()

我认为选项B比选项A更具可读性。由于代码的读取频率比编写频率高,我希望确保我(以及我们团队中的其他人)编写的所有代码都尽可能可读。

我想,使用您的注释,您需要做两件事:

  • 使程序更快
  • 使程序员工作更少(因为他们不必键入空检查)
对于第一个:空检查几乎不消耗任何资源。如果运行此示例:

public static void main(String[] args) {
    long ms = System.currentTimeMillis();
    for (int i=0;i<10000;i++) {
        returnsNonNull(i);
        doNothing();
    }
    System.out.println("Without nullcheck took "+(System.currentTimeMillis()-ms)+" ms to complete");

    ms = System.currentTimeMillis();
    for (int i=10000;i<20000;i++) {
        if (returnsNonNull(i)!=null) {
            doNothing();
        }
    }
    System.out.println("With nullcheck took "+(System.currentTimeMillis()-ms)+" ms to complete");
}

public static String returnsNonNull(int i) {
    return "Foo "+i+" Bar";
}
public static void doNothing() {

}
publicstaticvoidmain(字符串[]args){
长毫秒=System.currentTimeMillis();

对于(int i=0;i我建议如下:

  • 坚持使用
    @Nonnull
    @Nullable
    注释,就像您已经在做一样
  • 定义并强制默认值。默认值是什么并不重要,但在整个代码库中应该是相同的
  • 用于检查案例1和案例2。FindBugs有用于大多数IDE的插件,我看到Eclipse、Netbeans和IntelliJ提到过,但还有更多。(第2个案例包含在RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE规则中。我对其进行了测试。在阅读了本页其他地方的DavidHarkness评论后,我想我应该提到这一点。)

这种方法与IDE无关,也适用于外部构建环境,如Hudson或Jenkins。

如果您想执行此操作,请参见2)你非常依赖第三方去做它承诺的事情,而不是改变。这真的是你想要的吗?虽然它可能是内部的,但我更愿意采取防御措施,检查我的代码是否为空,如果其他代码违反了它的规定,我的代码是否会被破坏。收缩没有抓住实际的问题-你想要什么?我无法想象你想要移动一个与IntelliJ不同,因为它忽略了一个可能的诊断。您希望IntelliJ支持此诊断吗?如果您认为应该,请提交错误报告。Eclipse和Netbeans也是如此。最后一段是关于什么的?您可以创建一个实用方法,涵盖
null
案例并转到
Util.size(foo.getBars())
@Thomas因为
getBars()
根据契约永远不会返回
null
,所以不需要使用实用方法。@DavidMarkness您是对的,但这个想法是为了让程序员不必费劲去找出
getBars()
可以返回
null
也可以不返回。在最坏的情况下,实用程序方法可能会生成(最小值)调用方法的开销。默认情况下,我们使用包级注释将每个方法返回值、参数和字段标记为
@Nonnull
,因为很多代码在没有null的情况下更容易推理。如果程序员不使用
null
,他们必须在元素级重写它。结合单元测试还有FindBugs,这在过去的一年里避免了无数的麻烦。另外,要注意微观基准测试:JVM和JIT可以处理字节码,你永远不知道还有什么会占用CPU周期。最好在合同中有更多正式的信息。模糊合同从来都不好。我觉得这是目前为止最好的答案,所以我同意点击它。我将用FindBugs进行实验,看看它是否真的对案例2发出警告。在工作中再次测试。使用Maven和Eclipse插件,FindBugs只在比较中使用
!=
时生成警告——而不是在操作中使用相等的测试时。我为它提交了一个警告。使用
nonNullValue==null
是否会生成警告还是你?@DavidHarkness我的Eclipse编辑器。蓝色的bug标记是RCN_REDUNDANT_NULLCHECK_of_NONNULL_VALUE的出现。啊,我得到了与该代码相同的指示符,但如果我删除
| | getbar().size()>2
。我怀疑检测器认为空检查是多余的,只是因为对
null
值调用
size
会抛出异常。它实际上并没有检测到引用本身不能
null
@DavidHarkness啊,我明白你的意思了,这里也一样。感谢你发现这一点并提出这个问题.至于我的答案,我仍然推荐这种方法,即使我们看到有时错误检测器本身可能有错误。:-)总体而言,FindBugs在空指针分析方面做得相当好。
if (foo.getBars().size() < MAXIMUM_BARS && 
    baz.getFoos().size() < MAXIMUM_FOOS) {
  // do something
}
public static void main(String[] args) {
    long ms = System.currentTimeMillis();
    for (int i=0;i<10000;i++) {
        returnsNonNull(i);
        doNothing();
    }
    System.out.println("Without nullcheck took "+(System.currentTimeMillis()-ms)+" ms to complete");

    ms = System.currentTimeMillis();
    for (int i=10000;i<20000;i++) {
        if (returnsNonNull(i)!=null) {
            doNothing();
        }
    }
    System.out.println("With nullcheck took "+(System.currentTimeMillis()-ms)+" ms to complete");
}

public static String returnsNonNull(int i) {
    return "Foo "+i+" Bar";
}
public static void doNothing() {

}