未捕获的 RuntimeException 和 finally 子句:哪个先出现?

Posted

技术标签:

【中文标题】未捕获的 RuntimeException 和 finally 子句:哪个先出现?【英文标题】:Uncaught RuntimeException and finally clause: which comes first? 【发布时间】:2012-01-05 12:26:52 【问题描述】:

RuntimeException 被抛出 try 块而不被捕获,而 finally 子句调用 System.exit()

public static void main(String[] args) 
    try 
        Integer.valueOf("NotANumber");
     finally 
        System.out.println("finally");
        System.exit(0);
    

输出是

finally

如果 System.exit(0) 从 finally 中删除,则输出为

finally
Exception in thread "main" java.lang.NumberFormatException: For input string: "NotANumber"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:449)
    at java.lang.Integer.valueOf(Integer.java:554)
    at exception.MyExcepTest.main(MyExcepTest.java:20)

“finally”可能出现在NumberFormatException消息之前、之后或之间。

谁能解释一下?

【问题讨论】:

仅供参考,在我方便的系统上,上面有 Sun/Oracle 的 Java6(特别是“Java(TM) SE Runtime Environment (build 1.6.0_26-b03)”),我从来没有见过异常消息。我只看到“最后”那一行。而如果我删除 System.exit(0) 行,我会看到两者(可靠地首先是“finally”)。 【参考方案1】:

finally块肯定会在main方法退出之前执行,之后JVM会打印stacktrace。

也许堆栈跟踪被打印到 System.err,并且这两个流以不可预知的方式在控制台输出中混合在一起(因为它们基本上是同时产生的)。

当您也将“finally”打印到 System.err 时会发生什么?

【讨论】:

不是“也许”。这就是你看到这个的原因。未捕获的异常将打印到错误流中。未定义顺序的原因是您的控制台将取决于首先刷新哪个缓冲区。 好的,如果我将“finally”打印到 System.err,它似乎总是在 stacktrace 之前。【参考方案2】:

问题是,当抛出异常时.. JVM 第一次执行内部 finally 块的代码,然后如果捕获则抛出异常,否则它将抛出异常并终止线程。 所以这里当 System.exit(0) 出现在 finally 块中时,它会立即终止线程,这样 JVM 就没有机会抛出异常。 所以输出只是“最后 "

【讨论】:

【参考方案3】:

最终块总是被执行。它是由语言保证的。如果 try 块成功终止或抛出任何异常,则会执行它。

存在已检查和未检查的异常。对于未经检查的异常(运行时和错误),您不必编写 catch 块。但是所有异常都被打印堆栈跟踪的 JVM 捕获。当您的 finally 块终止应用程序时,它没有机会打印堆栈跟踪,因此您看不到它。

通常在 finally 块中退出程序是不好的,因为即使您的代码成功运行它也会退出。更一般地说,finally 块通常用于清理,如关闭文件、套接字等,而不是更复杂的业务逻辑。

【讨论】:

我调用 System.exit() 只是为了从我的 Java 应用程序中获取返回码。否则如果应用程序被 RuntimeException 中断,返回码是什么?【参考方案4】:

我们可以在 try 中使用两个块,它们是 catch 和 finally。

在抛出任何 RunTime 异常时(在 finally 之前)执行 catch 块,最后执行 finally 块,无论是否抛出异常。

所以如果你想对抛出的异常做些什么,那么你可以把它放在 catch(Excepion e) 块中。

您看到的是 JVM 有责任在终止程序执行之前执行 finally 块中写入的内容。

当程序终止时,默认情况下会显示抛出异常的踪迹。

【讨论】:

【参考方案5】:

即使在 try 块中的 return 语句的情况下,finally 方法总是会被执行,但在某些情况下,在 try 块中抛出错误(运行时内存)并不能保证 finally 块完全执行。

在您的情况下,由于您没有处理异常,因此 finally 块总是被执行并且由 JVM 的 main 方法抛出异常。

【讨论】:

请阅读此how-to-answer 并按照那里的指南提供高质量的答案。

以上是关于未捕获的 RuntimeException 和 finally 子句:哪个先出现?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 7致命错误:未捕获的RuntimeException:尚未设置外观根

将 laravel 5.8 升级到 6:致命错误:未捕获的 RuntimeException:尚未设置外观根

未捕获的异常'RuntimeException',消息'无法创建目录public / assets // node_modules / font-awesome / fonts

Java面试

springaop异常通知捕获的异常还能抛出去吗

HTML 部署中的 LibGDX 未捕获的运行时异常