1. 程式人生 > >try...catch...finally語句塊

try...catch...finally語句塊

try-catch-finally語句主要是用來處理檢查異常,捕獲並處理,以及最後必須要執行的finally塊。

try-catch-finally語句入門:

1.try-catch-finally語句的一般語法形式為:

    try {  

      // 可能會發生異常的程式程式碼  

    } catch (Type1 id1) {  

// 捕獲並處理try丟擲的異常型別Type1  

      } catch (Type2 id2) {  

// 捕獲並處理try丟擲的異常型別Type2  

      } finally {  

// 無論是否發生異常,都將執行的語句塊  

      }  

try 塊:用於捕獲異常。其後可接零個或多個catch塊,如果沒有catch塊,則必須跟一個finally塊。
catch 塊:用於處理try捕獲到的異常。
finally 塊:無論是否捕獲或處理異常,finally塊裡的語句都會被執行。當在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執行。

但是,在以下4種特殊情況下,finally塊不會被執行:
1)在finally語句塊中發生了異常。
2)在前面的程式碼中用了System.exit()退出程式。
3)程式所在的執行緒死亡。
4)關閉CPU。

2. try、catch、finally語句塊的執行順序:

1)當try沒有捕獲到異常時:try語句塊中的語句逐一被執行,程式將跳過catch語句塊,執行finally語句塊和其後的語句;

2)當try捕獲到異常,catch語句塊裡沒有處理此異常的情況:當try語句塊裡的某條語句出現異常時,而沒有處理此異常的catch語句塊時,此異常將會拋給JVM處理,finally語句塊裡的語句還是會被執行,但finally語句塊後的語句不會被執行;

3)當try捕獲到異常,catch語句塊裡有處理此異常的情況:在try語句塊中是按照順序來執行的,當執行到某一條語句出現異常時,程式將跳到catch語句塊,並與catch語句塊逐一匹配,找到與之對應的處理程式,其他的catch語句塊將不會被執行,而try語句塊中,出現異常之後的語句也不會被執行,catch語句塊執行完後,執行finally語句塊裡的語句,最後執行finally語句塊後的語句;

圖示try、catch、finally語句塊的執行:

此處有知識點:對於有多個catch子句的異常程式而言,應該儘量將捕獲底層異常類的catch子句放在前面,同時儘量將捕獲相對高層的異常類的catch子句放在後面。否則,捕獲底層異常類的catch子句將可能會被遮蔽。

try-catch-finally語句進階:

結論:
      1、不管有木有出現異常,finally塊中程式碼都會執行;
      2、當try和catch中有return時,finally仍然會執行;
      3、finally是在return後面的表示式運算後執行的(此時並沒有返回運算後的值,而是先把要返回的值儲存起來,管finally中的程式碼怎麼樣,返回的值都不會改變,任然是之前儲存的值),所以函式返回值是在finally執行前確定的;
      4、finally中最好不要包含return,否則程式會提前退出,返回值不是try或catch中儲存的返回值。
      

舉例:
情況1:try{} catch(){}finally{} return;
      顯然程式按順序執行。
情況2:try{ return; }catch(){} finally{} return;
      程式執行try塊中return之前的(包括return語句中的表示式運算)程式碼;
      再執行finally塊,最後執行try中return;
      finally塊之後的語句return,因為程式在try中已經return所以不再執行。
情況3:try{ } catch(){return;} finally{} return;
      程式先執行try,如果遇到異常執行catch塊,
      有異常:則執行catch中return之前的(包括return語句中的表示式運算)程式碼,再執行finally語句中全部程式碼,
      最後執行catch塊中return. finally之後也就是4處的程式碼不再執行。
      無異常:執行完try再finally再return.
情況4:try{ return; }catch(){} finally{return;}
      程式執行try塊中return之前(包括return語句中的表示式運算)程式碼;
      再執行finally塊,因為finally塊中有return所以提前退出。
情況5:try{} catch(){return;}finally{return;}
      程式執行catch塊中return之前(包括return語句中的表示式運算)程式碼;
      再執行finally塊,因為finally塊中有return所以提前退出。
情況6:try{ return;}catch(){return;} finally{return;}
      程式執行try塊中return之前(包括return語句中的表示式運算)程式碼;
      有異常:執行catch塊中return之前(包括return語句中的表示式運算)程式碼;
      則再執行finally塊,因為finally塊中有return所以提前退出。
      無異常:則再執行finally塊,因為finally塊中有return所以提前退出。


最終結論:任何執行try 或者catch中的return語句之前,都會先執行finally語句,如果finally存在的話。
          如果finally中有return語句,那麼程式就return了,所以finally中的return是一定會被return的,
          編譯器把finally中的return實現為一個warning。

下面是個測試程式:

public class Main {
    static int test() { 
        int x = 1; 
        try { 
            x++; 
            return x; 
        } finally { 
            ++x; 
        } 
    }
    
    public static void main(String[] args) { 
        Main m = new Main();
        System.out.println(m.test());
    }       
}

結果是2。

分析:在try語句中,在執行return語句時,要返回的結果已經準備好了,就在此時,程式轉到finally執行了。 在轉去之前,try中先把要返回的結果存放到不同於x的區域性變數中去,執行完finally之後,在從中取出返回結果, 因此,即使finally中對變數x進行了改變,但是不會影響返回結果。它應該使用棧儲存返回值。

原部落格:深入理解java異常處理機制

有return的情況下try catch finally的執行順序(最有說服力的總結)