【问题标题】:In Java, is the "finally" block guaranteed to be called (in the main method)?在 Java 中,是否保证调用“finally”块(在 main 方法中)?
【发布时间】:2010-10-05 16:30:58
【问题描述】:

我是一名 Java 菜鸟,我想知道,如果我有以下典型的 Java 代码

public class MyApp {
  public static void main(String[] args) {
    try {
      // do stuff
    } catch {
      // handle errors
    } finally {
      // clean up connections etc.
    }
  }
}

JVM 是否保证 finally 块将始终运行?为了理解我从哪里来,我已经习惯了 C/C++ 程序,如果你取消引用一个 NULL 指针并且你不能在此之后运行任何代码,那么这些程序可能会崩溃。

但据我了解 Java 和整个 GC / 托管内存业务,没有空指针取消引用之类的东西,一切都是可捕获的预期,所以我的程序实际上没有办法崩溃可以使它跳过最后,还是有?例如,在 Python 中,我通常会这样做

try:
  # do stuff
except AnExceptionIKnewMightHappen:
  # react in an appropriate way
except:
  # log that weird error I had not known could happen

而且我从来没有让任何应用程序在不通过我的代码的情况下死掉。

当然,如果操作系统出于某种原因终止了进程(或者如果某些事情终止了整个系统,例如拔掉插头),那么 Java 就无能为力了。此外,从 PHP 中,我知道你无法防范的不可捕获的错误,即使解释器在它发生后仍然存在(至少它能够输出正确的消息)。

编辑:为了清楚起见(实际上并没有被任何人误解),让我补充一下,我正在寻找在我的代码中可能导致终于被绕过了。所以指向 System.exit 是一个有用的提醒,尽管我不明白我为什么要这样做。

JVM 退出是一种相当明显的方式,我将其视为外部原因。指出您还必须记住线程在 JVM 和应用程序继续运行时退出的可能性非常有帮助,因为即使现在对我来说也很明显,但我没有想到。

【问题讨论】:

标签: java error-handling finally


【解决方案1】:

似乎很明显 nothing 将在 JVM 退出后运行,或者将在该终止线程中运行代码。明显的。因此,当 JVM 运行时,所有将运行的代码都会运行,并且在 JVM 退出或死线程后,nothing 将运行,即使是任何类型的代码。所以,没有办法阻止,但是如果需要finally子句,就放吧。

【讨论】:

    【解决方案2】:

    基本上是的,除了注释listed here(强调我的):

    如果在执行 try 或 catch 代码时 JVM 退出, 那么 finally 块可能不会执行。同样,如果线程 执行 try 或 catch 代码被中断或杀死,finally 块可能不会执行,即使应用程序作为一个整体 继续。

    【讨论】:

    • 请注意,拉电源线通常也是防止“finally”运行的好方法......
    • LOL - 如果是笔记本电脑,笔记本电脑中的电池会同时耗尽:D
    • 将笔记本电脑从摩天大楼的顶层丢下也可以防止 finally 块 关闭挂钩!!
    • 不。您引用的链接最终块 可能 不执行。它并没有说它不会执行。引用错误。
    • @Software Monkey 我想说这是错误的。因为在下落时有时间执行两个块(在极少数情况下,当你做一些非常耗时的事情时)。
    【解决方案3】:

    finally 块没有被执行的唯一异常是 JVM 崩溃或 system.exit()。

    【讨论】:

    • 我认为 finally 块在调用 System.exit() 时被调用。
    【解决方案4】:

    是的,JVM 总是执行它。保证。

    当然...如果 JVM 自身 死掉了(例如:System.exit()),那么它就无法保证任何事情。但是 JVM 死机不是 java 内的问题。

    【讨论】:

    • 这是不正确的。 Thread.stop() 可以防止 finally 在 JVM 仍在运行时阻塞。
    • @AlainO'Dea no,Thread.stop() 不会阻止 finally 块执行。
    • @Holger 情况比我最初想象的要微妙。 Thread.stop() 强制线程从任何地方抛出 ThreadDeath。在这里可以更好地描述其含义:stackoverflow.com/a/29373113/154527.
    • @AlainO'Dea 链接的答案很好地描述了这种情况。当线程在try 块内时Thread.stop() 不会阻止finally 的执行,但是当线程已经在finally 块内时它可能会阻止其完成。请注意,这些限制与普通代码流构造相同。如果线程永远不会到达try 块,则不会执行finally 块,此外,breakcontinue 针对try 构造或returnthrow 或任何外部的循环finally 块中引发的异常可能会阻止其完成。
    • @Holger 非常清楚。谢谢你。我认为这是最终处理过程中的停止引起了我最初的评论。我希望我能提供更多详细信息来说明我做出该回应的理由和更好的警告。
    【解决方案5】:

    克里斯卡梅隆是正确的。但通常会执行finally-block。 Java中确实存在空指针取消引用:

    try {
        List<Object> x = null;
        x.get(1); //throws the unchecked NullPointerException
    } finally {
        //will be executed
    }
    

    finally-Block 被执行。

    【讨论】:

    • 这很有趣,我不知道。虽然它仍然与经典的 C 段错误有很大不同。
    【解决方案6】:

    当然,finally 块每次都会运行。 JVM 崩溃或调用 exit() 函数的情况除外。我有代码,Java 应用程序调用了出现段错误的 JNI 本机代码。由此产生的崩溃杀死了 JVM,并阻止了 finally 的运行。

    【讨论】:

      【解决方案7】:

      总之,是的。

      Java 中 finally 块中的代码总是执行,除非:

      • 在 try 或 catch 块期间 JVM 退出
      • 运行代码的线程在 try 或 catch 块期间被中断或杀死

      (来自:http://java.sun.com/docs/books/tutorial/essential/exceptions/finally.html

      所以,除非你显式调用 System.exit(int),或者在外部终止进程或线程,否则你可以依赖它。

      【讨论】:

        【解决方案8】:

        不保证:

        public class Main {
            public static void main(String args[]) {
                try {
                    System.out.println("try");
                    System.exit(0);
                } catch (Exception e) {
                    System.out.println("exception");
                } finally {
                    System.out.println("finally");
                }
            }
        }
        

        运行它。

        【讨论】:

        • 不太清楚这与“所以我的程序没有真正的崩溃方法可以让它跳过 finally,或者是否存在?”显然,如果您退出 JVM,重新启动机器或拍摄监视器,那么最终将无法运行。对投票结果感到惊讶,但也许我只是嫉妒:)
        • 简单反例证明。显然不能保证。这对你来说可能重要也可能不重要。如果它发生在“干净”的出口上,我向你保证,在实际的崩溃中也不会更好。
        • 我认为可以肯定地说 System.exit() 是一个特例
        • 特殊与否,这是一个案例,也是一个有效的案例。 “最终保证”和“最终通常保证”之间存在巨大差异。
        • 添加我的 2ct,我认为这是一个有用的提醒,你实际上可以用普通代码绕过它(即没有错误),即使我现在想不出为什么我应该想以这种方式退出程序。我是 Java 新手,这对我很有帮助。
        【解决方案9】:

        是的,finally 块将始终运行,除非 JVM 崩溃(非常罕见,但可能会发生)。

        【讨论】:

          【解决方案10】:

          Erm,是的 :) 无论您的代码是否进入 catch,finally 都会运行。这是放置尝试后清理的代码的好地方。

          如果你破坏了jvm,它显然不会运行:)

          【讨论】:

            猜你喜欢
            • 2012-08-31
            • 2014-03-26
            • 2011-02-18
            • 1970-01-01
            • 2012-09-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多