try catch finally 執行順序面試題總結


 

在網上看到一些異常處理的面試題,試着總結一下,先看下面代碼,把這個方法在main中進行調用打印返回結果,看看結果輸出什么。

 

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;
}

 

沒錯,會按照順序執行,先執行try內代碼段,沒有異常的話進入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);
        }
}

 

輸出結果是:

 

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

 

代碼順序執行從try到finally,由於finally是無論如何都會執行的,所以try里的語句並不會直接返回。在try語句的return塊中,return返回的引用變量並不是try語句外定義的引用變量i,而是系統重新定義了一個局部引用i’,這個引用指向了引用i對應的值,也就是2,即使在finally語句中把引用i指向了值10,因為return返回的引用已經不是i,而是i',所以引用i的值和try語句中的返回值無關了。

 

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

 

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

 

打印結果如下:

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

 

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

 

好了,現在我們在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;
        }
}

 

輸出結果如下:

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

可以看到,是從finally語句塊中返回的。可見,JVM是忽略了try中的return語句。但IDE中會對finally中加的return有黃色警告提示,這是為什么呢,在try里加入一行會執行異常的代碼,如下:

 

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;
        }
}

 

打印結果如下:

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

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

那如果在finally中有異常發生,會對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里強行加上異常語句,打印結果如下:

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里發生異常,try、catch里的異常信息即被消化掉了,也達不到異常信息處理的目的。

 

總結以上測試:

1、finally語句總會執行

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

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

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

 

所以在實際項目中,finally常常是用來關閉流或者數據庫資源的,並不額外做其他操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM