2014-03-31 151 views
1

我发现使用@Nullable和@Nonnull注释参数和返回值非常方便。@Nullable Eclipse分析无法正常工作

然而,Eclipse分析似乎有点片面。我觉得follwing情况是真的很烦人:

public class SomeEntity { 
    private SomeObj someObj; 

    public void setSomeObj(@Nullable SomeObj someObj) { 
    this.someObj = someObj; 
    } 

    @Nullable public SomeObj getSomeObj() { 
    return someObj; 
    } 

    public boolean hasNewSomeObj() { 
    return someObj != null; 
    } 
} 

现在,当我提出以下称它给了我下面的Eclipse警告为错误: “潜在的空指针访问:该方法getZuordnenMitDatenuebernahme()可能返回null “

if(someEntity.hasNewSomeObj()) { 
    someOperator.doStuff(someEntity.getSomeObj().getSomething()); 
} 

即使如此,Null检查也被前面的方法调用覆盖。

有没有人有如何处理这个问题的好建议?我真的想保留我的注释返回值。

的Eclipse:朱诺第1版

的Java:1.6

JSR305实现:com.google.findbugs.jsr305 2.0.1

+0

这是Java 7还是Java 8(Eclipse在处理这些Java 8的方式上有变化)? –

+0

你所能做的就是使用'getSomeObj'方法并测试null。 –

+0

这将是一种耻辱,这种情况已经被大大降低了。还有其他一些情况有点复杂。 – dngfng

回答

1

if(someEntity.hasNewSomeObj()) { 
    someOperator.doStuff(someEntity.getSomeObj().getSomething()); 
} 

someEntity.getSomeObj()调用可能当您声明@Nullable时仍然返回null,因此调用getSomething()将导致NPE。

+0

如果someEntity.hanNewSomeObj()返回true,getSomeObj()如何返回null? – dngfng

+3

我不知道确切的代码,但是如果这个运行多线程,第二个线程可以在if(someEntity.hasNewSomeObj())和someEntity.getSomeObj()之间调用'someEntity.setSomeObj(null)'。getSomething )'。 – thr0wable

+0

不够公平,但我没有问过关于多线程。这仅仅是@Nullable/@ Nonnull Annoations未被正确评估的一个例子,因为简单的空检查会使错误标记消失。 – dngfng

2

其实@ thr0wable提供了一个很好的答案。

Eclipse编译器不可能保证,someEntity.getSomeObj()在调用someEntity.hasNewSomeObj()之后不会返回null,因为多个线程可以随时访问和修改someEntity

出于同样的原因,下面的代码也将产生很好的理由编译时错误:

if(someEntity.getSomeObj() != null) { 
    someOperator.doStuff(someEntity.getSomeObj().getSomething()); 
} 

保证的唯一方法,该对象实际上是不为空,是通过执行以下操作:

SomeObj o = someEntity.getSomeObj(); 
if(o != null) { 
    someOperator.doStuff(o.getSomething()); 
} 

UPDATE

与Java 8,你应该考虑使用Optional ,它提供完全的功能,你需要:

static class SomeEntity { 
    private Optional<Object> someObj; 

    public void setSomeObj(Object someObj) { 
     this.someObj = Optional.ofNullable(someObj); 
    } 

    public Optional<Object> getSomeObj() { 
     return someObj; 
    } 
} 

那么你的示例代码可以简化为这一点,使用lambda表达式时:

someEntity.getSomeObj().ifPresent(o -> System.out.println(o)); 

我不知道,如果编译时检查已经在最新的JDT Java 8 build中实现了,但是一旦它被发布,我认为如果你没有首先检查Optional#isPresent()而试图访问一个Optional对象,那么你肯定会得到编译时警告/错误。