Eclipse认为System.exit不会中断执行

5

我发现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的一个bug吗,还是在调用System.exit后仍有方法可以继续执行到r.nextInt()

我认为这更像是编译器的小问题,而不是 Eclipse 的问题,虽然这并不重要;-) - Chris Thompson
如果编译器警告对您造成了问题,您可以在 System.exit(1); 后添加一行 throw new RuntimeException("never happens"); ... 这将满足编译器的要求,在运行时,程序永远不会到达它,因此不会造成任何损害。 - Kevin K
2个回答

5

很好的问题,这也困扰了我好几次。

问题在于,与抛出异常不同,仅调用一个方法(而System.exit(1); 就是这个方法)通常不能保证程序流停止。 当然, System.exit()的文档说,此方法永远不会正常返回。 但是,虽然 throw 的语义由语言本身定义,但 System.exit()的语义仅在Javadocs中。

我猜他们只是没有费心去实现这种特殊情况。 虽然有一个错误报告涉及到此主题(https://bugs.eclipse.org/bugs/show_bug.cgi?id=126551,见注释2),但它被标记为“不修复”,因为看起来太复杂了。

编辑:正如rlegendi指出的那样,这实际上是Java编译器的问题,而不仅仅是Eclipse的问题。 我目前的解决方案是仅使用普通的 throw (而不是一些特殊的 throw()方法),这在除非是非常小的应用程序以外的任何情况下都比 System.exit()好。


1
“虽然 throw 的语义由语言本身定义,但 System.exit() 的语义仅在 Javadocs 中定义。” - Brian

1

这不是一个错误:在您的第二个示例中,保证在调用站点初始化了r(否则会抛出异常,因此执行分支已关闭)。

在第一个和第三个示例中,您只需执行程序代码并将r未定义。如果在异常处理块或声明时将其赋值为null,它将不会报错。

顺便说一句,这不是Eclipse的问题,而是由JLS定义的,您不能使用未初始化的变量。尝试使用Java编译它,您应该得到完全相同的输出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接