finally {}块不会执行的情况是什么?

在Java try{} ... catch{} ... finally{}块中, try{} ... catch{} ... finally{}代码通常被认为是“保证”运行,无论try / catch中发生了什么。 但是,我知道至少有两种情况不会执行:

  • 如果调用System.exit(0) ; 要么,
  • 如果exception被抛出到JVM并且发生默认行为(即printStackTrace()并退出)

是否有任何其他程序行为会阻止finally{}块中的代码执行? 代码在什么具体条件下执行?

编辑:正如NullUserException指出的那样,第二种情况实际上并非如此。 我认为这是因为标准错误中的文本在标准输出之后打印出来,防止文本在没有向上滚动的情况下被看到。 :) 道歉。

如果你调用System.exit() ,程序会立即退出而不会被调用。

JVM崩溃,例如Segmentation Fault,也会阻止最终被调用。 即JVM此时立即停止并生成崩溃报告。

无限循环也会阻止最终被调用。

抛出Throwable时始终会调用finally块。 即使你调用Thread.stop(),它也会触发在目标线程中抛出ThreadDeath 。 这可以被捕获(这是一个Error )并且将调用finally块。


 public static void main(String[] args) { testOutOfMemoryError(); testThreadInterrupted(); testThreadStop(); testStackOverflow(); } private static void testThreadStop() { try { try { final Thread thread = Thread.currentThread(); new Thread(new Runnable() { @Override public void run() { thread.stop(); } }).start(); while(true) Thread.sleep(1000); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testThreadInterrupted() { try { try { final Thread thread = Thread.currentThread(); new Thread(new Runnable() { @Override public void run() { thread.interrupt(); } }).start(); while(true) Thread.sleep(1000); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testOutOfMemoryError() { try { try { List bytes = new ArrayList(); while(true) bytes.add(new byte[8*1024*1024]); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testStackOverflow() { try { try { testStackOverflow0(); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testStackOverflow0() { testStackOverflow0(); } 

版画

 finally called after java.lang.OutOfMemoryError: Java heap space finally called after java.lang.InterruptedException: sleep interrupted finally called after java.lang.ThreadDeath finally called after java.lang.StackOverflowError 

注意:在每种情况下,线程都保持运行,即使在SO,OOME,Interrupted和Thread.stop()之后!

try块中的无限循环。

损坏内存 ? 程序不再按书面forms运行? 我实际上已经在DOS机器上调试了一次。

当最终自身抛出exception(或导致错误)时,有可能部分执行

一个可能是“最终是daeomon线程的一部分,它可能无法执行”。

最终不会被召唤的唯一时间是:

如果电源关闭

  1. 如果你调用System.exit()
  2. 如果JVM首先崩溃
  3. 如果try块中有无限循环
  4. 如果电源关闭

在try块中的不同语句中测试finally块。

  public static void main(String [] args){ try{ System.out.println("Before Statement"); /*** Statement ***/ System.out.println("After Statement"); } catch(Exception e){ } finally{ System.out.println("Finally is Executed"); } 

执行finally块的语句如下:

  1. Thread.currentThread().interrupted();
  2. Thread.currentThread().destroy();
  3. Thread.currentThread().stop();
  4. Thread.sleep(10);
  5. Thread.currentThread().interrupt();
  6. Runtime.getRuntime().addShutdownHook(Thread.currentThread());
  7. 如果发生任何exception。
  8. 如果没有例外。

不执行finally块的语句如下:

  1. Thread.currentThread().suspend();
  2. System.exit(0);
  3. JVM崩溃了。
  4. CPU芯片的电源关闭。
  5. 操作系统杀死了JVM进程。
  6. Runtime.getRuntime().exit(0);
  7. Runtime.getRuntime().halt(0);

我认为当JVM由于任何原因突然退出时,这可能是因为控件不会进入finally块而永远不会执行。

您可以将其作为守护程序线程的一部分。 您可以使用setDaemon(boolean status)方法,该方法用于将当前线程标记为守护程序线程或用户线程,并在需要时退出JVM。 这将使您能够在执行finally{}之前退出JVM。

finally块永远不会执行的另一个可能的实例是由于在输入try块之前返回方法的设计,就像我不时看到的一些非常糟糕的代码一样:

 public ObjectOfSomeType getMeAnObjectOfSomeType() throws SomeHorrendousException { if (checkSomeObjectState()) { return new ObjectOfSomeType(); } try { // yada yada yada... } catch (SomeHorrendousException shexc) { // wow, do something about this horrendous exception... } finally { // do some really important cleanup and state invalidation stuff... } 

我知道你们中没有人会这样做,所以我犹豫是否可以将此作为一种可能的情况加入,但是,想想,呃,这是星期五,到底是什么; )