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线程的一部分,它可能无法执行”。
最终不会被召唤的唯一时间是:
如果电源关闭
- 如果你调用System.exit()
- 如果JVM首先崩溃
- 如果try块中有无限循环
- 如果电源关闭
在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块的语句如下:
-
Thread.currentThread().interrupted();
-
Thread.currentThread().destroy();
-
Thread.currentThread().stop();
-
Thread.sleep(10);
-
Thread.currentThread().interrupt();
-
Runtime.getRuntime().addShutdownHook(Thread.currentThread());
- 如果发生任何exception。
- 如果没有例外。
不执行finally块的语句如下:
-
Thread.currentThread().suspend();
-
System.exit(0);
- JVM崩溃了。
- CPU芯片的电源关闭。
- 操作系统杀死了JVM进程。
-
Runtime.getRuntime().exit(0);
-
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... }
我知道你们中没有人会这样做,所以我犹豫是否可以将此作为一种可能的情况加入,但是,想想,呃,这是星期五,到底是什么; )