Java中finally關鍵字的幾個坑
java中的finally
關鍵字通常與try/catch
塊一起使用。用來在方法結束前或發生異常時做一些資源釋放的操作。雖然看起來很簡單,在日常開發中也發現幾個關於finlla
問題。
finally 語句塊一定會執行嗎?
很多人都認為finally
語句塊是肯定要執行的,比如下面的程式碼,只要進入了try/catch
塊,不管有沒有異常,都會執行finllay
塊 :
public static int test(){ try { System.out.println("try block"); int i = 1 / 0; return 0; } finally { System.out.println("finally block"); } }
執行程式碼輸出 :
try block finally block Exception in thread "main" java.lang.ArithmeticException: / by zero
但是回到這個問題,結果並不像大多人所認為的,答案是否定的,我們先來看下面這個例子:
public static int test(){ try { System.out.println("try block"); System.exit(0); return 0; } finally { System.out.println("finally block"); } }
執行程式碼輸出 :
try block
我們在try
語句塊中執行了System.exit (0)
語句,終止了 Java 虛擬機器的執行,finally
語句塊還是沒有執行。
如果執行了finally,函式返回值問題
public static int test(){ try { System.out.println("try block"); int i = 1 / 0; // 註釋 return 0; } catch (Exception e) { System.out.println("catch block"); return 1; } finally { System.out.println("finally block"); return 2; } }
對於上面的程式碼,相信大部分人都能知道輸出值是2
,列印結果也確實是2
,就算把int i = 1 / 0
這一行註釋掉,列印結果也是2
。所以在這裡我們可以下結論 :finally
裡的return
語句會把try/catch
塊裡的return
語句效果給覆蓋掉。
假如我們不在finally
中return
,結果會怎樣?我們再看看下面的例子 :
public static int test(){ int i = 999; try { System.out.println("try block"); i = 1 / 0; return i; } catch (Exception e) { System.out.println("catch block"); i = 100; return i; } finally { System.out.println("finally block"); i = 200; } }
列印結果是 :
try block catch block finally block 100
雖然呼叫了finllay
改變了i的值,但是最後輸出還是100
,為什麼呢?我們可以通過分析位元組碼檔案得到結果 :
public static int test(); Code: 0: sipush999 3: istore_0 。。。 29: getstatic#2// Field java/lang/System.out:Ljava/io/PrintStream; 32: ldc#14// String catch block 34: invokevirtual #10// Method java/io/PrintStream.println:(Ljava/lang/String;)V 37: bipush100 39: istore_0 40: iload_0 41: istore_2 42: getstatic#2// Field java/lang/System.out:Ljava/io/PrintStream; 45: ldc#12// String finally block 47: invokevirtual #10// Method java/io/PrintStream.println:(Ljava/lang/String;)V 50: sipush200 53: istore_0 54: iload_2 55: ireturn 。。。
從位元組碼檔案中可以看出,在37:39
中把100
存入index 0
的位置,就是設定i
的值為100
,在40:41
中把index 0
的值賦值給了index 2
的位置,在50:53
中把200
存入index 0
的位置,就是設定i
的值為200
,最後在54:55
中把index 2
的值加載出來並返回,即最後返回的是index 2
的值100
。
對於這種情況我的理解就是在return
的的時候會把返回值壓入棧,並把返回值賦值給棧中的區域性變數, 最後把棧頂的變數值作為函式返回值。所以在finally
中的返回值就會覆蓋try/catch中
的返回值,如果finally
中不執行return
語句,在finally
中修改返回變數的值,不會影響返回結果。