我发现Eclipse报告“局部变量可能尚未初始化”错误的方式存在奇怪的二分法。如果我在try / catch块之外声明一个变量,在try / catch块中初始化它,然后在try / catch块之后使用它,通常会发生此错误:
Random r;
try {
r = new AESCounterRNG();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
r.nextInt(); //Error: The local variable r may not have been initialized
这是有道理的。我可以通过在声明它时将变量初始化为null
来避免错误,或通过确保程序的控制流永远不会到达下一个语句(如果try / catch中发生异常)块。因此,如果变量初始化失败,我真的无法继续执行,我可以这样做:
Random r;
try {
r = new AESCounterRNG();
} catch (GeneralSecurityException e) {
throw new RuntimeException("Initialize secure random number generator failed");
}
r.nextInt(); //No error here
但是,我最近尝试使用System.exit
来停止程序而不是RuntimeException
来使程序的控制台输出更清晰。我认为这些都是等价的,因为两者都阻止程序继续执行,但我发现Eclipse不同意:
Random r;
try {
r = new AESCounterRNG();
} catch (GeneralSecurityException e) {
System.err.println("Couldn't initialize secure random number generator");
System.exit(1);
}
r.nextInt(); //Error: The local variable r may not have been initialized
如果发生异常,执行永远无法达到r.nextInt()
,为什么Eclipse仍然会给我“未初始化”错误?这是Eclipse中的错误,还是某种方式即使在调用r.nextInt()
之后执行仍可继续System.exit
?
答案 0 :(得分:5)
好问题,它也多次惹我生气。
问题在于,抛出一个异常,只是调用一个方法(那就是System.exit(1);
)通常不能保证程序流程停止。当然,the documentation of System.exit()说这种方法永远不会正常返回。但是虽然throw
的语义是由语言本身定义的,但System.exit()
的语义只是在Javadoc中。
我的猜测是,他们还没有费心去实施这个特殊情况。虽然有一个错误报告,其中涉及该主题(https://bugs.eclipse.org/bugs/show_bug.cgi?id=126551,请参阅注释2),但它被标记为“不会修复”,因为它似乎太复杂了。
编辑:正如rlegendi指出的那样,它实际上是Java编译器的一个问题,而不仅仅是Eclipse。到目前为止,我的解决方案是使用普通的throw
,(而不是一些特殊的throw()
方法),除了非常小的应用程序之外,其他任何东西都优于System.exit()
答案 1 :(得分:1)
这不是一个错误:在你的第二个例子中,保证在调用站点初始化r
(否则抛出一个exeption,以便关闭执行分支)。
在第一个和第三个例子中,您只需执行程序代码并保持r
未定义。如果您在异常处理区或声明处为其分配null
,则不会抱怨。
顺便说一下,这不是Eclipse问题,JLS定义您不能使用未初始化的变量。尝试用Java编译它,你应该得到完全相同的输出。