以前跟別人討論finally關鍵字,我總是簡單的說:“fianly代碼塊中的代碼一定會執行,一般用來清除IO資源等非內存資源(內存資源由GC機制回收)”。 今天翻書發現了幾種不會執行的情況,現在總結下。
1.finally的含義
finally的真正含義是指從try代碼塊出來才一定會執行相應的finally代碼塊。
public class Test { public static void main(String[] args) { foo(false); } public static void foo(boolean flag) { System.out.println("enter foo()"); if(flag) { try { System.out.println("enter try block"); } finally { System.out.println("enter finally block"); } } else { System.out.println("leave foo()"); } } } /****************** 控制台打印如下 enter foo() leave foo() *******************/
上述代碼,flag為false,沒有進入try代碼塊,對應的finally自然也不會執行。
2.System.exit()
System.exit()的作用是中止當前虛擬機,虛擬機都被中止了,finally代碼塊自然不會執行。
public class Test { public static void main(String[] args) { foo(); } public static void foo() { System.out.println("enter foo()"); try { System.out.println("enter try block"); System.exit(); } finally { System.out.println("enter finally block"); } } } /***************** 控制台打印如下 enter foo() enter try block ******************/
上述代碼,進入foo()方法后再進入try代碼塊,但是在進入finally代碼塊之前調用了System.exit()中止虛擬機, finally代碼塊不會被執行。
3.守護(daemon)線程被中止時
java線程分為兩類,守護線程和非守護線程。當所有的非守護線程中止時,不論存不存在守護線程,虛擬機都會kill掉守護線程從而中止程序。 虛擬機中,執行main方法的線程就是一個非守護線程,垃圾回收則是另一個守護線程,main執行完,程序就中止了,而不管垃圾回收線程是否中止。 所以,如果守護線程中存在finally代碼塊,那么當所有的非守護線程中止時,守護線程被kill掉,其finally代碼塊是不會執行的。
public class Test { public static void main(String[] args) { Thread t = new Thread(new Task()); t.setDaemon(true); //置為守護線程 t.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { throw new RuntimeException("the "+Thread.currentThread().getName()+" has been interrupted",e); } } } class Task implements Runnable { @Override public void run() { System.out.println("enter run()"); try { System.out.println("enter try block"); TimeUnit.SECONDS.sleep(5); //阻塞5s } catch(InterruptedException e) { System.out.println("enter catch block"); throw new RuntimeException("the "+Thread.currentThread().getName()+" has been interrupted",e); } finally { System.out.println("enter finally block"); } } } /******************* 控制台打印如下 enter run() enter try block ********************/
上述代碼,main()執行完,非守護線程也就結束了,雖然線程t處於阻塞狀態,但由於其是守護線程,所以程序仍會中止。 而且,即使其進入了try代碼塊,finally代碼塊也不會被執行。
總結
finally代碼塊並非一定執行,在不進入try代碼塊或者程序被中止時就不會執行。
引用
1.《Java編程思想》