2、為什么要用finally
先看一個沒有finally的異常處理try-catch語句:
假設count為要使用到的資源,並且用完要求釋放此資源。那么我們可以把釋放資源的語句放到try-catch后執行,當前的程序不管是在執行完try語句塊還是catch語句塊,都會順序執行到下面釋放資源的語句。
int count = 0; //初始化資源
try{
count++;
if(count == 1) throw new Exception("Exception in try");
}catch(Exception e){
System.out.println("catch block");
}
count = 0; //釋放資源
但是,如果在try或catch中有多條return語句,那么在每條return語句之前,都要先執行釋放資源的語句:
public void f() throws Exception {
int count = 0; //初始化資源
try{
doSomething;
statementMayCauseException;
//可能會拋出異常的語句,若異常沒有被catch,則直接拋出,也不會執行到try-catch下面的語句,因為這個異常被系統處理就是打印了異常棧的信息之后就結束了這個程序,也就是結束了這個進程。
doSomething;
if(count == 1) throw new Exception1("E1 in try");
if(count == 2) throw new Exception2("E2 in try");
}catch(Exception1 e){
count = 0; //釋放資源
throw e; //再次把異常拋出,讓上一級捕獲。此時將不會執行catch外的語句,所以要先釋放資源
}catch(Exception2 e){
count = 0; //釋放資源
return; //返回了,也不會執行catch外的語句,所以要先釋放資源
}
count = 0;
//釋放資源,其實count=0程序不會執行這里的因為在執行期間先獲得了前面的那個return語句所以后面就不會執行了。
}
這樣,就需要在每一個可能返回的地方,以及每一個可能出現異常而導致程序跳轉的地方,考慮如何釋放資源,導致復雜和冗余。
所以,需要finally語句。
把資源釋放或狀態還原的代碼放到finally塊中,可以保證在try和catch語句執行完后,一定會執行finally語句塊,而不用考慮各種復雜的跳轉情況。
1、int count = 0;
try{
count++;
if(count == 1)throw new Exception();
}catch(Exception e){
}finally{
count = 0;
}
2.finally什么時候執行
finally在return語句之后,跳轉到上一級程序之前執行。
1 public class Test { 2 3 public static void main(String[] args) { 4 System.out.println(test()); 5 } 6 7 public static String test() { 8 try { 9 System.out.println("try block"); 10 return test1(); 11 } finally { 12 System.out.println("finally block"); 13 // return "finally"; 14 } 15 } 16 17 public static String test1() { 18 System.out.println("return statement"); 19 return "after return"; 20 } 21 }
結果:
try block
return statement
finally block
after return

分析:
1.try語句塊,return test1(),則調用test1方法
2.test1()執行后返回"after return",返回值"after return"保存在一個臨時區域里
3.執行finally語句塊。若finally語句有返回值,則此返回值將替換掉臨時區域的返回值
4.再將臨時區域的返回值送到上一級方法中。
try、catch、finally 這個過程也就是這樣,如果try catch finally 都有return:
1、在沒有異常的情況下,try 中的返回值先保存到臨時區域里在去執行finally ,這個finally 有返回值,這個返回值將之前try中的保存到臨時區域的值用返回的這個值替換,再將這個臨時區域中的值返回給上一級方法。
2、如果有異常,則執行catch中的代碼,這里的return 將返回一個返回值放到臨時區域,再去執行finally ,這個finally有返回值,這樣就將catch中存在臨時區域中的值用這個finally 返回的值替換掉,在將這個臨時區域的值返回給上一級方法。
如果finally語句有返回值,則此返回值將會替換掉臨時區域原有的值。
參考:
《thinking in Java》
2,驗證finally真正執行順序
1 import java.io.FileInputStream; 2 3 public class Test1 { 4 public static void main(String[] args) { 5 Test1 m = new Test1(); 6 System.out.println(m.amethod()); 7 } 8 9 public int amethod() { 10 try { 11 // 1,拋出異常 12 FileInputStream dis = new FileInputStream("test1.txt"); 13 } catch (Exception ex) { 14 // 2.catch捕獲異常,並執行 15 System.out.println("No such file found"); 16 // 4,return 返回 17 return -1; 18 } finally { 19 // 3.finally一定會在return之前執行。(准確說,應該是return;語句) 20 System.out.println("Done finally"); 21 } 22 return 0; 23 } 24 }
輸出結果為:
總結:
finally其實是僅在return 語句執行前執行,如果return一個函數,那么會先執行函數,但如果函數內有(return)語句,那么finally就會在這個return 語句前執行。finally在catch中的return之前執行但是如果catch中有返回值而finally中也有返回值的話finally中的返回值會替換catch中的返回值,因為catch中的返回值是存放在一個臨時區中,try 中的過程和catch 是一樣的。
如果catch塊有異常向外拋出,執行順序呢:我執行我,你拋你得異常,我finally我的語句,我倆互不干涉,你別管我啥時執行,但我一定會執行。
關於finally,此時,應該很明朗了只需記着一點:除非調用system.exit()讓程序退出也就是將調用這個程序的進程斷開了退出了這個程序就不會執行或斷電等因素致使程序停止進程終止,否則無論任何因素finally塊都一定會執行。
本文轉載自 http://blog.csdn.net/qh_java/article/details/12583803 2017-06-0916:48:23 么么噠!!!
