我发现了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
?
好问题,它也多次困扰我。
问题是,抛出一个异常,只是调用一个方法(这就是System.exit(1);
)通常不能保证程序流程停止。当然,the documentation of System.exit()说这种方法永远不会正常返回。但是,虽然throw
的语义是由语言本身定义的,但System.exit()
的语义只是在Javadocs中。
我的猜测是他们只是没有费心去实施这个特殊情况。虽然有一个错误报告,这个主题被触及(https://bugs.eclipse.org/bugs/show_bug.cgi?id=126551,见注释2),它被标记为“不会修复”,因为它似乎太复杂。
编辑:正如rlegendi指出的那样,它实际上是Java编译器的一个问题,而不仅仅是Eclipse。到目前为止,我的解决方案是使用普通的旧throw
(而不是一些特殊的throw()
方法),除了一个非常小的应用程序之外,其他任何东西都比System.exit()
更好。
这不是一个错误:在你的第二个例子中,保证r
在调用站点初始化(否则抛出一个exeption,以便执行分支关闭)。
在第一个和第三个例子中,您只需执行程序代码并保持r
未定义。如果你在异常处理块或声明中将null
分配给它,它就不会抱怨。
顺便说一下,它不是Eclipse问题,它由JLS定义,您不能使用未初始化的变量。尝试用Java编译它,你应该得到完全相同的输出。