【问题标题】:Uncaught RuntimeException and finally clause: which comes first?未捕获的 RuntimeException 和 finally 子句:哪个先出现?
【发布时间】: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”)。

标签: java try-catch-finally runtimeexception


【解决方案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 并按照那里的指南提供高质量的答案。
      猜你喜欢
      • 2019-01-15
      • 2013-07-24
      • 1970-01-01
      • 2015-05-12
      • 2021-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多