(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 location
。 obj
实际上是null
还是为什么编译器会这么认为?
答案 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();