問:finally語句必定會執行嗎?
答:java
若是沒有執行相應的try語句則不會執行。segmentfault
在try語句中若是調用System.exit(0)方法則不會執行。佈局
問:finally會在何時執行?
答:若是在try/catch語句中調用轉移指令例如:return,break,continue,throw等。則會在轉移指令前執行。code
若是在finally中含有return語句,那麼try/catch語句的return還有做用嗎?對象
先看一段代碼:blog
/** * Created by gavin on 15-9-2. */ public class FinallyTest { public static void main(String[] args){ System.out.println(test1()); //3 System.out.println(test2()); //3 System.out.println(test3()); //2 System.out.println(test4()); //2 } public static int test1() { int i = 1; try { i = 2; return i; }finally { i++; return i; } } public static int test2() { int i = 1; try { i = 2; return i; }finally { i = 3; return i; } } public static int test3() { int i = 1; try { i = 2; return i; }finally { i++; } } public static int test4() { int i = 1; try { i = 2; return i; }finally { i = 3; } } }
若是你對java內存佈局不是很清楚,請看這篇文章:java虛擬機類加載機制和字節碼執行引擎內存
重點關注運行時棧幀結構(局部變量表槽
,操做數棧
)。get
上邊的代碼很是簡單,來看一下字節碼指令吧虛擬機
public static int test1(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=3, args_size=0 0: iconst_1 //定義一個常量1入棧到操做數棧 //棧1 0: 1: 1: istore_0 //出棧,存儲到局部便量表槽0 //棧 0:1 1: 2: iconst_2 //定義一個常量2入棧到操做數棧 //棧2 0:1 1: 3: istore_0 //出棧,存儲到局部變量表槽0 //棧 0:2 1: 4: iload_0 //從局部便量表槽0入棧到操做數棧 //棧2 0:2 1: 5: istore_1 //出棧,存儲到局部變量表槽1 //棧 0:2 1:2 6: iinc 0, 1 //局部變量表槽0變量加1 //棧 0:3 1:2 9: iload_0 //從局部變量表槽0入棧到操做數棧 //棧3 0:3 1:2 10: ireturn //結束,返回 //棧3 0:3 1:2 11: astore_2 12: iinc 0, 1 15: iload_0 16: ireturn public static int test2(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=3, args_size=0 0: iconst_1 //定義一個常量1入棧到操做數棧 //棧1 0: 1: 1: istore_0 //出棧,存儲到局部便量表槽0 //棧 0:1 1: 2: iconst_2 //定義一個常量2入棧到操做數棧 //棧2 0:1 1: 3: istore_0 //出棧,存儲到局部變量表槽0 //棧 0:2 1: 4: iload_0 //從局部變量表槽0入棧 //棧2 0:2 1: 5: istore_1 //出棧,存儲到局部變量表槽1 //棧 0:2 1:2 6: iconst_3 //定義一個常量3入棧 //棧3 0:2 1:2 7: istore_0 //出棧,存儲到局部便量表槽0 //棧 0:3 1:2 8: iload_0 //從局部變量表槽0入棧 //棧3 0:3 1:2 9: ireturn //結束,返回 //棧3 0:3 1:2 10: astore_2 11: iconst_3 12: istore_0 13: iload_0 14: ireturn public static int test3(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=3, args_size=0 0: iconst_1 //定義一個常量1入棧到操做數棧 //棧1 0: 1: 1: istore_0 //出棧,存儲到局部便量表槽0 //棧 0:1 1: 2: iconst_2 //定義一個常量2入棧到操做數棧 //棧2 0:1 1: 3: istore_0 //出棧,存儲到局部變量表槽0 //棧 0:2 1: 4: iload_0 //從局部變量表槽0入棧 //棧2 0:2 1: 5: istore_1 //出棧,存儲到局部變量表槽1 //棧 0:2 1:2 6: iinc 0, 1 //局部變量表槽0變量加一 //棧 0:3 1:2 9: iload_1 //從局部變量表槽1入棧 //棧2 0:3 1:2 10: ireturn //結束,返回 //棧2 0:3 1:2 11: astore_2 12: iinc 0, 1 15: aload_2 16: athrow public static int test4(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=3, args_size=0 0: iconst_1 //定義一個常量1入棧到操做數棧 //棧1 0: 1: 1: istore_0 //出棧,存儲到局部便量表槽0 //棧 0:1 1: 2: iconst_2 //定義一個常量2入棧到操做數棧 //棧2 0:1 1: 3: istore_0 //出棧,存儲到局部變量表槽0 //棧 0:2 1: 4: iload_0 //從局部變量表槽0入棧 //棧2 0:2 1: 5: istore_1 //出棧,存儲到局部變量表槽1 //棧 0:2 1:2 6: iconst_3 //定義一個常量3入棧到操做數棧 //棧3 0:2 1:2 7: istore_0 //出棧,存儲到局部變量表槽0 //棧 0:3 1:2 8: iload_1 //從局部變量表槽1入棧 //棧2 0:3 1:2 9: ireturn //結束,返回 //棧2 0:3 1:2 10: astore_2 11: iconst_3 12: istore_0 13: aload_2 14: athrow
咱們看到:it
在finally中沒有return時,棧中最後存儲的數據是try/catch中操做後數據。即finally操做後的數據存儲到其餘槽中,然後再加載try/catch操做後的數據。
而在finally中含有return時,棧中最後存儲的數據是finally中操做後的數據。即finally操做後的數據存儲到其餘槽中,然後加載的是其餘槽(finally)中的數據。
也就是說:若是finally中不含有return語句,finally對try/catch操做的八大基礎類型不會再加載到操做數棧中。
若是返回值是對象引用,finally中的return還有待考據。