Java try catch finally的執(zhí)行順序解讀
try catch finally 執(zhí)行順序結(jié)論
- 不管有沒(méi)有出現(xiàn)異常,finally塊中代碼都會(huì)執(zhí)行;
- 當(dāng)try和catch中有return時(shí),finally仍然會(huì)執(zhí)行;
- finally是在return后面的表達(dá)式運(yùn)算后執(zhí)行的(此時(shí)并沒(méi)有返回運(yùn)算后的值,而是先把要返回的值保存起來(lái),不管finally中的代碼怎么樣,返回的值都不會(huì)改變,任然是之前保存的值),所以函數(shù)返回值是在finally執(zhí)行前確定的;
- finally中最好不要包含return,否則程序會(huì)提前退出,返回值不是try或catch中保存的返回值。
案例1
public class FinallyTest {
public static void main(String[] args) {
System.out.print(new FinallyTest().test1());
}
int test1(){
int x = 1;
try {
return ++x;
}finally {
++x;
}
}
}2
分析:在try語(yǔ)句中,在執(zhí)行return語(yǔ)句時(shí),要返回的結(jié)果已經(jīng)準(zhǔn)備好了,就在此時(shí),程序轉(zhuǎn)到finally執(zhí)行了。
在轉(zhuǎn)去之前,try中先把要返回的結(jié)果存放到不同于x的局部變量中去,執(zhí)行完finally之后,在從中取出返回結(jié)果,
因此,即使finally中對(duì)變量x進(jìn)行了改變,但是不會(huì)影響返回結(jié)果。
案例2
public class FinallyTest {
public static void main(String[] args) {
System.out.print(new FinallyTest().test2());
}
int test2(){
int i = 1;
try{
i++;
System.out.println("try block, i = "+i);
}catch(Exception e){
i++;
System.out.println("catch block i = "+i);
}finally{
i = 10;
System.out.println("finally block i = "+i);
}
return i;
}
}try block, i = 2
finally block i = 10
10
沒(méi)錯(cuò),會(huì)按照順序執(zhí)行,先執(zhí)行try內(nèi)代碼段,沒(méi)有異常的話進(jìn)入finally,最后返回。
案例3
public class FinallyTest {
public static void main(String[] args) {
System.out.print(new FinallyTest().test3());
}
int test3(){
int i = 1;
try{
i++;
System.out.println("try block, i = "+i);
return i;
}catch(Exception e){
i ++;
System.out.println("catch block i = "+i);
return i;
}finally{
i = 10;
System.out.println("finally block i = "+i);
}
}
}try block, i = 2
finally block i = 10
2
分析:代碼順序執(zhí)行從try到finally,由于finally是無(wú)論如何都會(huì)執(zhí)行的,所以try里的語(yǔ)句并不會(huì)直接返回。在try語(yǔ)句的return塊中,return返回的引用變量并不是try語(yǔ)句外定義的引用變量i,而是系統(tǒng)重新定義了一個(gè)局部引用 i,這個(gè)引用指向了引用 i 對(duì)應(yīng)的值,也就是 2,即使在finally語(yǔ)句中把引用 i 指向了值 10 ,因?yàn)閞eturn返回的引用已經(jīng)不是 i ,而是 i ,所以引用i的值和try語(yǔ)句中的返回值無(wú)關(guān)了。
包裝類型
但是,這只是一部分,如果把 i 換成引用類型而不是基本類型呢,來(lái)看看輸出結(jié)果怎樣,示例如下:
public class FinallyTest {
public static void main(String[] args) {
System.out.print(new FinallyTest().testWrap());
}
List<Object> testWrap(){
List<Object> list = new ArrayList<>();
try{
list.add("try");
System.out.println("try block");
return list;
}catch(Exception e){
list.add("catch");
System.out.println("catch block");
return list;
}finally{
list.add("finally");
System.out.println("finally block ");
}
}
}try block
finally block
main test i = [try, finally]
可以看到,finally里對(duì)list集合的操作生效了,這是為什么呢。我們知道基本類型在棧中存儲(chǔ),而對(duì)于非基本類型是存儲(chǔ)在堆中的,返回的是堆中的地址,因此內(nèi)容被改變了。
案例4
現(xiàn)在我們?cè)趂inally里加一個(gè)return,看看語(yǔ)句是從哪里返回的。
public class FinallyTest {
public static void main(String[] args) {
System.out.print(new FinallyTest().test3());
}
int test3(){
int i = 1;
try{
i++;
System.out.println("try block, i = "+i);
return i;
}catch(Exception e){
i ++;
System.out.println("catch block i = "+i);
return i;
}finally{
i = 10;
System.out.println("finally block i = "+i);
return i; //HERE
}
}
}try block, i = 2
finally block i = 10
10
可以看到,是從finally語(yǔ)句塊中返回的。可見(jiàn),JVM是忽略了try中的return語(yǔ)句。但I(xiàn)DE中會(huì)對(duì)finally中加的return有黃色警告提示,這是為什么呢。
案例5
在try里加入一行會(huì)執(zhí)行異常的代碼,如下:
public class FinallyTest {
public static void main(String[] args) {
System.out.print(new FinallyTest().test3());
}
int test3(){
int i = 1;
try{
i++;
int m = i / 0; // HERE
System.out.println("try block, i = "+i);
return i;
}catch(Exception e){
i ++;
System.out.println("catch block i = "+i);
return i;
}finally{
i = 10;
System.out.println("finally block i = "+i);
return i;
}
}
}catch block i = 3
finally block i = 10
10
可以看到,因?yàn)閒inally中有return語(yǔ)句,try、catch中的異常被消化掉了,屏蔽了異常的發(fā)生,這與初期使用try、catch的初衷是相違背的,因此編譯器也會(huì)提示警告。
案例6
那如果在finally中有異常發(fā)生,會(huì)對(duì)try、catch中的異常有什么影響呢?
public class FinallyTest {
public static void main(String[] args) {
System.out.print(new FinallyTest().test3());
}
int test3(){
int i = 1;
try{
i++;
System.out.println("try block, i = "+i);
return i;
}catch(Exception e){
i ++;
System.out.println("catch block i = "+i);
return i;
}finally{
i = 10;
int m = i / 0; // HERE
System.out.println("finally block i = "+i);
return i;
}
}
}try block, i = 2
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.shigeqiu.demo.FinallyTest.test3(FinallyTest.java:21)
at com.shigeqiu.demo.FinallyTest.main(FinallyTest.java:6)
這個(gè)提示表示的是finally里的異常信息,也就是說(shuō)一旦finally里發(fā)生異常,try、catch里的異常信息即被消化掉了,也達(dá)不到異常信息處理的目的。
總結(jié)
總結(jié)以上測(cè)試:
- finally語(yǔ)句總會(huì)執(zhí)行
- 如果try、catch中有return語(yǔ)句,finally中沒(méi)有return,那么在finally中修改除包裝類型和靜態(tài)變量、全局變量以外的數(shù)據(jù)都不會(huì)對(duì)try、catch中返回的變量有任何的影響(包裝類型、靜態(tài)變量會(huì)改變、全局變量)
- 盡量不要在finally中使用return語(yǔ)句,如果使用的話,會(huì)忽略try、catch中的返回語(yǔ)句,也會(huì)忽略try、catch中的異常,屏蔽了錯(cuò)誤的發(fā)生
- finally中避免再次拋出異常,一旦finally中發(fā)生異常,代碼執(zhí)行將會(huì)拋出finally中的異常信息,try、catch中的異常將被忽略
所以在實(shí)際項(xiàng)目中,finally常常是用來(lái)關(guān)閉流或者數(shù)據(jù)庫(kù)資源的,并不額外做其他操作。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring boot actuator監(jiān)控超詳細(xì)教程
Spring Boot Actuator就是一款可以幫助你監(jiān)控系統(tǒng)數(shù)據(jù)的框架,其可以監(jiān)控很多很多的系統(tǒng)數(shù)據(jù),接下來(lái)通過(guò)本文給大家介紹spring boot actuator監(jiān)控超詳細(xì)教程,感興趣的朋友一起看看吧2021-10-10
海量數(shù)據(jù)去重排序bitmap(位圖法)在java中實(shí)現(xiàn)的兩種方法
今天小編就為大家分享一篇關(guān)于海量數(shù)據(jù)去重排序bitmap(位圖法)在java中實(shí)現(xiàn)的兩種方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02
springboot2?使用activiti6?idea插件的過(guò)程詳解
這篇文章主要介紹了springboot2?使用activiti6?idea插件,本文通過(guò)截圖實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
Java實(shí)現(xiàn)的百度語(yǔ)音識(shí)別功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的百度語(yǔ)音識(shí)別功能,較為簡(jiǎn)明扼要的分析了Java調(diào)用百度語(yǔ)音接口相關(guān)操作步驟,并給出了具體的語(yǔ)音識(shí)別用法代碼示例,需要的朋友可以參考下2018-08-08
web.xml?SpringBoot打包可執(zhí)行Jar運(yùn)行SpringMVC加載流程
這篇文章主要為大家介紹了web.xml?SpringBoot打包可執(zhí)行Jar運(yùn)行SpringMVC加載流程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
springboot中@Async默認(rèn)線程池導(dǎo)致OOM問(wèn)題
這篇文章主要介紹了springboot中@Async默認(rèn)線程池導(dǎo)致OOM問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Nacos配置文件使用經(jīng)驗(yàn)及CAP原則詳解
這篇文章主要為大家介紹了Nacos配置文件使用經(jīng)驗(yàn)及CAP規(guī)則詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-02-02
如何通過(guò)java實(shí)現(xiàn)highcharts導(dǎo)出圖片至excel
這篇文章主要介紹了如何通過(guò)java實(shí)現(xiàn)highcharts導(dǎo)出圖片至excel。文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們就來(lái)一起學(xué)習(xí)一下吧2019-06-06
如何正確控制springboot中bean的加載順序小結(jié)篇
這篇文章主要介紹了如何正確控制springboot中bean的加載順序總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07

