finally語句塊對返回的影響
阿新 • • 發佈:2020-10-15
Java中用於異常處理的語句方法為:
try { //... } catch (Excaption e){ //... } finally { //... }
其中finally語句塊是一定會執行的,不論是正常返回還是丟擲異常。
那麼就引出一個問題:當在try/catch語句中已經return 返回一個變數,此時再次在finally中操作返回變數或重新return會對原來的返回值造成什麼影響?
1、finally中修改返回變數
/** 在finally語句塊中修改返回變數的值 */ static int testFinallyAndReturn1(){int i=10; try{ return i; }finally{ i=i+1; } }
public static void main(String[] args) { int return1 = testFinallyAndReturn1(); System.out.println(return1); //結果為10 }
結果返回依然是return的值,可以說在finally中操作已經return的變數,不會對返回結構有影響。
口說無憑,使用 javap -c
static int testFinallyAndReturn1(); Code: 模擬棧和區域性變量表的儲存內容,棧的左側為棧頂,區域性變量表依次索引為0,1,2,... 0: bipush 10 # 向運算元棧中放入常量10 棧:10 區域性變量表: 2: istore_0 # 將棧頂元素放入區域性變量表的slot 0位置 值為10 棧: 區域性變量表:103: iload_0 # 取出區域性變量表slot 0的值入棧 值為10 棧:10 區域性變量表:10 4: istore_1 # 棧頂元素存入slot 1 值為10 棧: 區域性變量表:10 10 5: iload_0 # 區域性變量表slot 0入棧 值為10 棧:10 區域性變量表:10 10 6: iconst_1 # 常量1入棧 棧:1 10 區域性變量表:10 10 7: iadd # 棧頂2個元素出棧並相加,結果再入棧 值為11 棧:11 區域性變量表:10 10 8: istore_0 # 棧頂元素存入slot 0 值為11 棧: 11 10 9: iload_1 # slot 1入棧 棧:10 11 10 10: ireturn # 棧頂元素返回 11: astore_2 # 下面是出現異常時的指令。。。。 12: iload_0 13: iconst_1 14: iadd 15: istore_0 16: aload_2 17: athrow Exception table: from to target type 3 5 11 any
從上面的位元組碼指令可以看到,雖然return程式碼寫在前面,但是在執行位元組碼時,還是先執行finally的加1操作。
finally做加法操作與return操作的變數,分別被儲存到區域性變量表不同slot中,所以finally中操作變數不會影響返回值。
2、finally中再次return
/** 在finally語句塊中修改返回變數的值,並再次返回變數 */ static int testFinallyAndReturn2(){ int i=10; try{return i; }finally{ i=i+1; return i; } } //---------------------- public static void main(String[] args) { int return2 = testFinallyAndReturn2(); System.out.println(return2); //11 }
結果:finally中返回的值會覆蓋掉之前return的值
位元組碼如下:
static int testFinallyAndReturn2(); Code: 0: bipush 10 2: istore_0 3: iload_0 4: istore_1 # 這裡沒有用到??? 5: iload_0 6: iconst_1 7: iadd 8: istore_0 9: iload_0 # 不同點在這裡,返回指令前入棧的是slot 0 值為11 10: ireturn 11: astore_2 12: iload_0 13: iconst_1 14: iadd 15: istore_0 16: iload_0 17: ireturn Exception table: from to target type 3 5 11 any
3、finally的返回值會覆蓋掉丟擲的異常
如下,這段程式碼會正常返回11,而不是丟擲異常。
static int testFinallyAndReturn2(){ int i=10; try{ int a = i/0; return i; }finally{ i=i+1; return i; } }
這段是finally中無返回值時的部分指令:
15: astore_3
16: iload_0
17: iconst_1
18: iadd
19: istore_0
20: aload_3
21: athrow #丟擲異常
//----------------------------------------------
這個是finally中有返回值時的部分指令:
15: astore_3
16: iload_0
17: iconst_1
18: iadd
19: istore_0
20: iload_0
21: ireturn #返回
finally中如果有返回值語句,就會用return指令覆蓋掉異常丟擲指令。所以說最好不要在finally中返回結果。
4、簡單總結
- finally語句塊中僅修改返回變數,不會影響最終的返回結果
- finally語句塊中有返回語句,會覆蓋之前的返回值
- finally語句塊中有返回語句,會覆蓋丟擲的異常,使異常無法丟擲