奇怪的Java编译器警告:错误的“潜在的空访问警告”

时间:2011-07-21 06:30:07

标签: java nullpointerexception compiler-warnings

(JDK 1.6.0_23,Eclipse 3.7.0,“潜在空指针访问”警告级别为“警告”)请考虑以下示例代码:

Object obj = null;
for (;;) {
    obj = getObject();
    if (obj != null) break;
    Thread.sleep(25);
}
obj.toString();

我在最后一行收到以下警告:Potential null pointer access: The variable obj may be null at this locationobj实际上是null还是为什么编译器会这么认为?

5 个答案:

答案 0 :(得分:8)

我会说编译器将其视为:

Object obj = null;
[Too dumb to interpret this loop]
obj.toString();

因此,如果无法解释循环的作用,obj.toString()可能为null。

例如,您可以通过替换:

来欺骗编译器
void x(int x){
    return;  
    x++;  //error unreachable code
}

void x(int x){
    if(true) return;
    x++;  //compiles
}

答案 1 :(得分:4)

似乎编译器无法很好地分析代码。它实际上无法“运行”它并且理解您的if语句阻止了空访问。我玩了一些代码,发现以下等效版本没有产生警告:

    Object obj = null;
    do {
        obj = getObject();
        if (obj == null) {
            Thread.sleep(25);
        }
    } while (obj == null);
    obj.toString();

是的,我知道这个版本对每个循环迭代执行2次空检查而不是一次。因此,您需要更改代码,将@SuppressWarning添加到代码中或删除Thread.sleep(25)

答案 2 :(得分:3)

编译器将此视为未初始化对象的可能性。它实际上无法看到循环中断条件是对象不为null或者它将永远运行或直到它不再为null。我只收到你提到的JDK的警告。使用更新版本时,不会出现此警告。

答案 3 :(得分:3)

这是AlexR代码的改进版本,我认为这是一个很好的解决方案,同时也提高了代码的可读性。我的版本有第二行obj = getObject();行,但不需要第二次检查,因此它应该更具整体性能。

Object obj = null;
obj = getObject();
while (obj == null) {
    Thread.sleep(25);
    obj = getObject();
}
obj.toString();

答案 4 :(得分:0)

我知道这是一个老线程,但是这个怎么样?我发现它比Koraktor和AlexR的版本更具可读性。

Object obj = null;
for (obj=getObject(); obj==null; obj=getObject()) {
  Thread.sleep(25);
}
obj.toString();

但在我的代码中,我通常在eclipse编译器设置中启用“在null分析中包含'断言'并添加一个断言。所以我不必改变控制流程,同时避免警告:

Object obj = null;    
while (true) {
    obj = getObject();
    if (obj != null) break;
    Thread.sleep(25);
}
assert obj!=null;
obj.toString();