今天就跟大家聊聊有關(guān)try、finally與return語句在Java中哪個(gè)先執(zhí)行,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括淶源網(wǎng)站建設(shè)、淶源網(wǎng)站制作、淶源網(wǎng)頁制作以及淶源網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,淶源網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到淶源省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
Demo1
public class Test { public static void main(String[] args) { System.out.println("return value of test(): " + test()); } public static int test() { int i = 1; // if (i == 1) { // return 0; // } System.out.println("the previous statement of try block"); i = i / 0; try { System.out.println("try block"); return i; } finally { System.out.println("finally block"); } } }
Demo1的執(zhí)行結(jié)果如下:
the previous statement of try block Exception in thread "main" java.lang.ArithmeticException: / by zero at com.becoda.bkms.bus.basics.web.Test2.test(Test2.java:15) at com.becoda.bkms.bus.basics.web.Test2.main(Test2.java:5)
另外,如果去掉上例中的注釋,執(zhí)行結(jié)果則是:
return value of test(): 0
以上兩種情況,finally語句塊都沒有執(zhí)行,說明什么問題?只有與finally相對應(yīng)的try語句塊得到執(zhí)行的情況下,finally語句塊才會執(zhí)行,而上面都是在try語句塊之前返回(return)或者拋出異常,所以try對應(yīng)的finally語句塊沒有執(zhí)行。那么,即使與finally相對應(yīng)的try語句塊得到執(zhí)行的情況下,finally語句塊一定會執(zhí)行嗎?但下面例子
Demo2
public class Test { public static void main(String[] args) { System.out.println("return value of test(): " + test()); } public static int test() { int i = 1; try { System.out.println("try block"); System.exit(0); return i; } finally { System.out.println("finally block"); } } }
Demo2的執(zhí)行結(jié)果如下:
try block
finally語句塊還是沒有執(zhí)行,為什么呢?因?yàn)槲覀冊趖ry語句塊中執(zhí)行了System.exit(0)語句,終止了Java虛擬機(jī)的運(yùn)行,雖然一般情況下我們不會這么干。還有情況是當(dāng)一個(gè)線程在執(zhí)行try語句塊或者catch語句塊時(shí)被打斷(interrupted)或者被終止(killed),與其對應(yīng)的finally語句塊可能不會執(zhí)行。還有更極端的情況,就是在線程運(yùn)行 try 語句塊或者 catch 語句塊時(shí),突然死機(jī)或者斷電,finally 語句塊肯定不會執(zhí)行了。
finally 語句示例說明
下面看一個(gè)簡單的例子
Demo3
public class Test { public static void main(String[] args) { try { System.out.println("try block"); return; } finally { System.out.println("finally block"); } } }
Demo3的執(zhí)行結(jié)果為:
try block finally block
Demo3說明 finally 語句塊在 try 語句塊中的 return 語句之前執(zhí)行。我們再來看另一個(gè)例子。
Demo4
public class Test { public static void main(String[] args) { System.out.println("reture value of test() : " + test()); } public static int test() { int i = 1; try { System.out.println("try block"); i = 1 / 0; return 1; } catch (Exception e) { System.out.println("exception block"); return 2; } finally { System.out.println("finally block"); } } }
Demo4的執(zhí)行結(jié)果為:
try block exception block finally block reture value of test() : 2
Demo4說明了 finally 語句塊在 catch 語句塊中的 return 語句之前執(zhí)行。
從上面的Demo3和Demo4,我們可以看出,其實(shí)finally語句塊時(shí)在try或者catch中的return語句之前執(zhí)行的,更加一般的說法是,finally語句塊應(yīng)該是在控制轉(zhuǎn)移語句之前執(zhí)行,控制轉(zhuǎn)移語句除了return外,還有break和continue。
再來看下面兩個(gè)例子
Demo5
public class Test { public static void main(String[] args) { System.out.println("return value of getValue(): " + getValue()); } public static int getValue() { try { return 0; } finally { return 1; } } }
Demo5的執(zhí)行結(jié)果為:
return value of getValue(): 1
Demo6
public class Test { public static void main(String[] args) { System.out.println("return value of getValue(): " + getValue()); } public static int getValue() { int i = 1; try { return i; } finally { i++; } } }
Demo6的執(zhí)行結(jié)果為:
return value of getValue(): 1
利用我們上面分析得出的結(jié)論:finally 語句塊是在 try 或者 catch 中的 return 語句之前執(zhí)行的。 由此,可以輕松的理解Demo5 的執(zhí)行結(jié)果是 1。因?yàn)?finally 中的 return 1;語句要在 try 中的 return 0;語句之前執(zhí)行,那么 finally 中的 return 1;語句執(zhí)行后,把程序的控制權(quán)轉(zhuǎn)交給了它的調(diào)用者 main()函數(shù),并且返回值為 1。那為什么Demo6 的返回值不是 2,而是 1 呢?按照Demo5 的分析邏輯,finally 中的 i++;語句應(yīng)該在 try 中的 return i;之前執(zhí)行???i 的初始值為 1,那么執(zhí)行 i++;之后為 2,再執(zhí)行 return i;那不就應(yīng)該是 2 嗎?怎么變成 1 了呢?
說明這個(gè)問題需要了解Java虛擬機(jī)是如何編譯finally語句塊的。
Java方法是在棧幀中執(zhí)行,棧幀是線程私有棧的單位,執(zhí)行方法的線程會為每一個(gè)方法分配一小塊空間來作為該方法執(zhí)行時(shí)的內(nèi)存空間,棧幀分為三個(gè)區(qū)域:
1、操作數(shù)棧,用來保存正在執(zhí)行的表達(dá)式中的操作數(shù)
2、局部變量區(qū),用來保存方法中使用的變量,包括方法參數(shù),方法內(nèi)部聲明的變量,以及方法中使用到的對象的成員變量或類的成員變量(靜態(tài)變量),最后兩種變量會復(fù)制到局部變量區(qū),因此在多線程環(huán)境下,這種變量需要根據(jù)需要聲明為volatile類型
3、字節(jié)碼指令區(qū)
例如下面這段代碼
try{ return expression; }finally{ do some work; }
首先我們知道,finally語句是一定會執(zhí)行,但他們的執(zhí)行順序是怎么樣的呢?他們的執(zhí)行順序如下:
1、執(zhí)行:expression,計(jì)算該表達(dá)式,結(jié)果保存在操作數(shù)棧頂;
2、執(zhí)行:操作數(shù)棧頂值(expression的結(jié)果)復(fù)制到局部變量區(qū)作為返回值;
3、執(zhí)行:finally語句塊中的代碼;
4、執(zhí)行:將第2步復(fù)制到局部變量區(qū)的返回值又復(fù)制回操作數(shù)棧頂;
5、執(zhí)行:return指令,返回操作數(shù)棧頂?shù)闹担?/p>
我們可以看到,在第一步執(zhí)行完畢后,整個(gè)方法的返回值就已經(jīng)確定了,由于還要執(zhí)行finally代碼塊,因此程序會將返回值暫存在局部變量區(qū),騰出操作數(shù)棧用來執(zhí)行finally語句塊中代碼,等finally執(zhí)行完畢,再將暫存的返回值又復(fù)制回操作數(shù)棧頂。所以無論finally語句塊中執(zhí)行了什么操作,都無法影響返回值,所以試圖在finally語句塊中修改返回值是徒勞的。因此,finally語句塊設(shè)計(jì)出來的目的只是為了讓方法執(zhí)行一些重要的收尾工作,而不是用來計(jì)算返回值的。
這樣就能解釋Demo6的問題了
讓我們再來看以下 3 個(gè)例子。
Demo7
public class Test { public static void main(String[] args) { System.out.println("return value of getValue(): " + getValue()); } @SuppressWarnings("finally") public static int getValue() { int i = 1; try { i = 4; } finally { i++; return i; } } }
Demo7的執(zhí)行結(jié)果為:
return value of getValue(): 5
Demo8
public class Test { public static void main(String[] args) { System.out.println("return value of getValue(): " + getValue()); } public static int getValue() { int i = 1; try { i = 4; } finally { i++; } return i; } }
Demo8的執(zhí)行結(jié)果為:
return value of getValue(): 5
Demo9
public class Test { public static void main(String[] args) { System.out.println(test()); } public static String test() { try { System.out.println("try block"); return test1(); } finally { System.out.println("finally block"); } } public static String test1() { System.out.println("return statement"); return "after return"; } }
Demo9的執(zhí)行結(jié)果為:
try block return statement finally block after return
總結(jié):
1、finally 語句塊不一定會被執(zhí)行
2、finally 語句塊在 try 語句塊中的 return 語句之前執(zhí)行
3、finally 語句塊在 catch 語句塊中的 return 語句之前執(zhí)行
4、finally 語句塊中的 return 語句會覆蓋 try 塊中的 return 返回
5、試圖在 finally 語句塊中修改返回值不一定會被改變
看完上述內(nèi)容,你們對try、finally與return語句在Java中哪個(gè)先執(zhí)行有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。