finally代碼塊不被執行的情況總結


以前跟別人討論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編程思想》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM