{轉載}java Finally塊中程式碼什麼時候執行
問題描述:try{}裡有一個return語句,那麼緊跟在這個try{}後面的finally{}中的程式碼是否會被執行?如果會的話,什麼時候被執行,在return之前還是return之後?
在Java語言的異常處理中,finally塊的作用就是為了保證無論出現什麼情況,finally塊裡的程式碼一定會被執行。由於程式執行return就意味著結束對當前函式的呼叫並跳出這個函式體,因此任何語句要執行都只能在return前執行(除非碰到exit函式),因此finally塊裡的程式碼也是在return之前執行的。此外,如果try-finally或者catch-finally中都有return,那麼finally塊中的return將會覆蓋別處的return語句,最終返回到呼叫者那裡的是finally中return的值。下面通過一個例子來說明這個問題:
package com.js; /** * try-catch中有return語句,finally中程式碼執行時機問題 * @author jiangshuai */ public class Test{ public static int testFinally(){ try { return 1; } catch (Exception e) { return 0; }finally{ System.out.println("execute finally"); } } public static void main(String[] args){ int result = testFinally(); System.out.println(result); } } 執行結果: execute finally 1 從上面這個例子中可以看出,在執行return語句前確實執行了finally塊中的程式碼。緊接著,在finally塊裡放置個return語句,來看看到底最終返回的是哪個return語句的值,例子如下圖所示: package com.js; /** * try-catch中有多個return語句,研究return的是哪一個 * @author jiangshuai */ public class Test{ public static int testFinally(){ try { return 1; } catch (Exception e) { return 0; }finally{ System.out.println("execute finally"); return 3; } } public static void main(String[] args){ int result = testFinally(); System.out.println(result); } }
執行結果:
execute finally
3
從以上執行結果可以看出,當finally塊中有return語句時,將會覆蓋函式中其他return語句。此外,由於在一個方法內部定義的變數都儲存在棧中,當這個函式結束後,其對應的棧就會被回收,此時在其方法體中定義的變數將不存在了,因此,對基本型別的資料,在finally塊中改變return的值對返回值沒有任何影響,而對引用型別的資料會有影響(詳見
Java中的值傳遞與引用傳遞詳解 )。下面通過一個例子來說明這個問題:
package com.js; /** * 在finally塊中改變基本資料型別、引用型別對比 * @author jiangshuai */ public class Test{ public static int testFinally1(){ int result = 1; try { result = 2; return result; } catch (Exception e) { return 0; }finally{ result = 3; System.out.println("execute finally1"); } } public static StringBuffer testFinally2(){ StringBuffer s = new StringBuffer("Hello"); try { return s; } catch (Exception e) { return null; }finally{ s.append(" World"); System.out.println("execute finally2"); } } public static void main(String[] args){ int result = testFinally1(); System.out.println(result); StringBuffer resultRef = testFinally2(); System.out.println(resultRef); } }
執行結果:
execute finally1
2
execute finally2
Hello World
程式在執行到return時會首先將返回值儲存在一個指定的位置,其次去執行finally塊,最後再返回。在方法testFinally1中呼叫return前,先把result的值1儲存在一個指定的位置,然後再去執行finally塊中的程式碼,此時修改result的值將不會影響到程式的返回結果。testFinally2中,在呼叫return前先把s儲存到一個指定的位置,由於s為引用型別,因此在finally中修改s將會修改程式的返回結果。
引申:出現在Java程式中的finally塊是不是一定會被執行?
答案:不一定。
下面給出兩個finally塊不會被執行的例子:
1)、當程式進入try塊之前就出現異常時,會直接結束,不會執行finally塊中的程式碼,示例如下:
package com.js;
/**
* 在try之前發生異常
* @author jiangshuai
*/
public class Test{
public static void testFinally1(){
int result = 1/0;
try {
System.out.println("try block");
} catch (Exception e) {
System.out.println("catch block");
}finally{
System.out.println("finally block");
}
}
public static void main(String[] args){
testFinally1();
}
}
執行結果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.js.Test.testFinally1(Test.java:9)
at com.js.Test.main(Test.java:19)
程式在執行1/0時會丟擲異常,導致沒有執行try塊,因此finally塊也就不會被執行。
2)、當程式在try塊中強制退出時也不會去執行finally塊中的程式碼,示例如下:
package com.js;
/**
* 在try之前發生異常
* @author jiangshuai
*/
public class Test{
public static void testFinally1(){
try {
System.out.println("try block");
System.exit(0);
} catch (Exception e) {
System.out.println("catch block");
}finally{
System.out.println("finally block");
}
}
public static void main(String[] args){
testFinally1();
}
}
執行結果:
try block
上例在try塊中通過呼叫System.exit(0)強制退出了程式,因此導致finally塊中的程式碼沒有被執行。