try catch finally 執(zhí)行順序

在網(wǎng)上看到一些異常處理的面試題,試著總結(jié)一下,先看下面代碼,把這個方法在main中進(jìn)行調(diào)用打印返回結(jié)果,看看結(jié)果輸出什么。

 public static  int testBasic(){
       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;
}

沒錯,會按照順序執(zhí)行,先執(zhí)行try內(nèi)代碼段,沒有異常的話進(jìn)入finally,最后返回,那么輸出如下:

try block, i = 2
finally block i = 10
main test i = 10

這個沒有問題,如果我們把return語句放入try catch里又會怎么樣呢?

public static  int testBasic(){
       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);
       }
}

輸出結(jié)果是:

try block, i = 2
finally block i = 10
main test i = 2

代碼順序執(zhí)行從try到finally,由于finally是無論如何都會執(zhí)行的,所以try里的語句并不會直接返回。在try語句的return塊中,return返回的引用變量并不是try語句外定義的引用變量i,而是系統(tǒng)重新定義了一個局部引用i’,這個引用指向了引用i對應(yīng)的值,也就是2,即使在finally語句中把引用i指向了值10,因?yàn)閞eturn返回的引用已經(jīng)不是i,而是i',所以引用i的值和try語句中的返回值無關(guān)了。

但是,這只是一部分,如果把i換成包裝類型而不是基本類型呢,來看看輸出結(jié)果怎樣,示例如下:

public static  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 ");
       }
}

打印結(jié)果如下:

try block
finally block
main test i = [try, finally]

可以看到,finally里對list集合的操作生效了,這是為什么呢。我們知道基本類型在棧中存儲,而對于非基本類型是存儲在堆中的,返回的是堆中的地址,因此內(nèi)容被改變了。

好了,現(xiàn)在我們在finally里加一個return,看看語句是從哪里返回的。

public static  int testBasic(){
       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;
       }
}

輸出結(jié)果如下:

try block, i = 2
finally block i = 10
main test i = 10

可以看到,是從finally語句塊中返回的??梢姡琂VM是忽略了try中的return語句。但I(xiàn)DE中會對finally中加的return有黃色警告提示,這是為什么呢,在try里加入一行會執(zhí)行異常的代碼,如下:

public static  int testBasic(){
       int i = 1; 
       try{
           i++;
           int m = i / 0 ;
           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;
       }
}

打印結(jié)果如下:

catch block i = 3
finally block i = 10
main test i = 10

可以看到,因?yàn)閒inally中有return語句,try、catch中的異常被消化掉了,屏蔽了異常的發(fā)生,這與初期使用try、catch的初衷是相違背的,因此編譯器也會提示警告。

那如果在finally中有異常發(fā)生,會對try、catch中的異常有什么影響呢?

public static  int testBasic(){
       int i = 1; 
       try{
           i++;
           Integer.parseInt(null);
           System.out.println("try block, i = "+i);
           return i;
       }catch(Exception e){
           String.valueOf(null);
           System.out.println("catch block i = "+i);
           return i;
       }finally{
           i = 10;
           int m = i / 0;
           System.out.println("finally block i = "+i);
       }
}

這里我們在try、catch里強(qiáng)行加上異常語句,打印結(jié)果如下:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at tryandcatch.TryAndCatch.testBasic(TryAndCatch.java:25)
at tryandcatch.TryAndCatch.main(TryAndCatch.java:45)

這個提示表示的是finally里的異常信息,也就是說一旦finally里發(fā)生異常,try、catch里的異常信息即被消化掉了,也達(dá)不到異常信息處理的目的。

總結(jié)以上測試:

1、finally語句總會執(zhí)行

2、如果try、catch中有return語句,finally中沒有return,那么在finally中修改除包裝類型和靜態(tài)變量、全局變量以外的數(shù)據(jù)都不會對try、catch中返回的變量有任何的影響(包裝類型、靜態(tài)變量會改變、全局變量)

3、盡量不要在finally中使用return語句,如果使用的話,會忽略try、catch中的返回語句,也會忽略try、catch中的異常,屏蔽了錯誤的發(fā)生

4、finally中避免再次拋出異常,一旦finally中發(fā)生異常,代碼執(zhí)行將會拋出finally中的異常信息,try、catch中的異常將被忽略

所以在實(shí)際項目中,finally常常是用來關(guān)閉流或者數(shù)據(jù)庫資源的,并不額外做其他操作。

注意String new 和 "" 是不一樣的。

1.String str1 = "abc";

String str2 = "abc";

sysout(str1==str2) 為 TRUE

解釋:棧中str1和str2都直接指向常量池中“abc”,==比較地址,地址一樣。

String str1 = "abc";

String str2 = new String(“abc”);

sysout(str1==str2);為FALSE

解釋:str1指向常量池中“abc”,str2指向堆中新開辟的空間,所以地址不一樣。

String str1 = "abc";

Stirng str2 = “ab”;

str2=str2+“c”;

sysout(str1==str2);為FALSE

解釋:str1指向常量池“abc”,str2指向堆中新開辟的空間,故地址不同。

String str1 = new String(“abc”);

String str2 = new String(“abc”);

sysout(str1==str2);為FALSE

解釋:str1指向堆中開辟的空間,str2在堆中又重新開辟了空間,兩者并不是同一個空間,故地址不同。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容