首頁 > 軟體

Java中try-catch-finally執行順序你知道嗎

2022-06-17 18:03:05

引言

java例外處理中,try、catch、finally的執行順序,大家都知道是按順序執行的,這裡我就不廢話了。但是當try、catch、finally中加入return之後,就會有幾種不同的情況出現,下面分別來說明一下。也可以跳到最後直接看總結。

正文

這裡共列舉五種情況,會對其一一說明。

try塊中有return

try{
    System.out.println("try塊程式碼執行了");
    return 0;
}catch(Exception e){
    System.out.println("catch塊程式碼執行了");
}finally {
    System.out.println("finally塊程式碼執行了");
}
return 1;

輸出結果:

try塊程式碼執行了
finally塊程式碼執行了

最終返回:0

執行流程:

執行try塊中return前(包括return語句中的表示式運算)的程式碼 -> 執行finally塊 -> 執行try中return。

結論:

當try中帶有return時,會先執行return前的程式碼,然後暫時儲存需要return的資訊,再執行finally中的程式碼,最後再通過return返回之前儲存的資訊。finally塊之後的語句return不再執行,因為程式在try中已經return過了,方法的執行已經結束。

但有一點需要注意,如果返回值是參照型別呢?再看另外一個例子:

List<Integer> list = new ArrayList<>();
try {
    list.add(0);
    System.out.println("try:" + list);
    return list;
} catch (Exception e) {
    list.add(1);
    System.out.println("catch:" + list);
} finally {
    list.add(2);
    System.out.println("finally:" + list);
}
return list;

輸出:

try:[0]
finally:[0,2]

最終返回:[0,2]

看完這個例子,可能會發現問題,剛提到return時會臨時儲存需要返回的資訊,不受finally塊中程式碼的影響。但是在這裡,list裡存的不是變數本身,而是變數的地址,所以當finally通過地址改變了變數,還是會影響方法返回值的。

catch塊中有return

try{
    System.out.println("try塊程式碼執行了");
    //int x = 1 / 0 ;
}catch(Exception e){
    System.out.println("catch塊程式碼執行了");
    return 0;
}finally {
    System.out.println("finally塊程式碼執行了");
}
return 1;

輸出結果:

//無異常
try塊程式碼執行了
finally塊程式碼執行了
    
最終返回:1
//有異常
try塊程式碼執行了
catch塊程式碼執行了
finally塊程式碼執行了
    
最終返回:0

執行流程:

程式先執行try,如果遇到異常執行catch塊。

有異常:執行catch中return之前(包括return語句中的表示式運算)程式碼,再執行finally語句中全部程式碼,最後執行catch塊中return, finally之後的return不再執行。

無異常:執行完try再finally再return。

結論:

catch中return與try中類似,若出現異常,會暫時儲存catch塊中return的資訊,再執行finally中的程式碼,最後再通過return返回之前儲存的資訊。

try塊和finally塊中有return

try{
    System.out.println("try塊程式碼執行了");
    return 0;
}catch(Exception e){
    System.out.println("catch塊程式碼執行了");
​
}finally {
    System.out.println("finally塊程式碼執行了");
    return 1;
}

輸出結果:

try塊程式碼執行了
finally塊程式碼執行了
    
最終返回:1

執行流程:

程式執行try塊中return之前(包括return語句中的表示式運算)程式碼,再執行finally塊。因為finally塊中有return所以提前退出,而不再執行try中的return。

備註:

這種寫法是可以編譯通過的,但是編譯器會給予警告。我們一般不在finally塊中寫return語句,這裡只是刻意演示了一下效果。

catch塊和finally塊中有return

try{
    System.out.println("try塊程式碼執行了");
    //int x = 1 / 0 ;
}catch(Exception e){
    System.out.println("catch塊程式碼執行了");
    return 0;
}finally {
    System.out.println("finally塊程式碼執行了");
    return 1;
}

輸出結果:

//無異常
try塊程式碼執行了
finally塊程式碼執行了
    
最終返回:1

//有異常
try塊程式碼執行了
catch塊程式碼執行了
finally塊程式碼執行了
    
最終返回:1

執行流程:

無異常:執行try後跳過catch執行finally,得到finally的返回值1;

有異常:程式執行catch塊中return之前(包括return語句中的表示式運算)程式碼,再執行finally塊。因為finally塊中有return所以提前退出,而不再執行catch中的return。

try塊、catch塊和finally塊中都有return

try{
    System.out.println("try塊程式碼執行了");
    //int x = 1 / 0 ;
    return 0;
}catch(Exception e){
    System.out.println("catch塊程式碼執行了");
    return 1;
}finally {
    System.out.println("finally塊程式碼執行了");
    return 2;
}

輸出結果:

//無異常
try塊程式碼執行了
finally塊程式碼執行了

最終返回:2
    
//有異常
try塊程式碼執行了
catch塊程式碼執行了
finally塊程式碼執行了

最終返回:2    

執行流程:

程式執行try塊中return之前(包括return語句中的表示式運算)程式碼,

無異常:然後再執行finally塊,因為finally塊中有return所以提前退出;

有異常:執行catch塊中return之前(包括return語句中的表示式運算)程式碼,再執行finally塊。因為finally塊中有return所以提前退出

結論:

得到finally中的返回值3。

總結

  • 無論catch是否捕獲異常,finally語句塊都是要被執行的。

  • 當try塊或catch塊return一個值,那麼finally塊中的程式碼會在執行return後,返回之前執行。(此時並沒有返回運算後的值,而是把要返回的值暫時儲存起來)。

  • finally中如果包含return,那麼程式將在這裡返回,而不是通過try或catch中的return返回,返回值就不是try或catch中儲存的返回值了。會直接在finally中結束方法的執行,導致try、catch中的return失效

  • 當try或catch,finally中都包含return的時候,要注意返回值的型別。finally修改的基本型別是不影響返回結果的,修改list、map、自定義類等參照型別時,是影響返回結果的。

  • 編譯器會對finally中的return給予警告,因為從finally中返回可能會導致異常丟失 。如:

    try
    {
        try
        {
            throw new RuntimeException("來自try塊中的異常") ;
        }finally{  
            return;
        }
    }
    catch (Exception e)
    {
        e.printStackTrace(System.out) ;
    }

    這裡無法捕獲 我們自定義的執行時異常。

    又如:

    try
    {
        try
        {
            throw new RuntimeException("來自try塊中的異常") ;
        }finally{
            throw new RuntimeException("來自finally塊中的異常") ;
        }
    }
    catch (Exception e)
    {
        e.printStackTrace(System.out) ;
    }

    這裡會丟失 第一個異常。

到此這篇關於try-catch-finally執行順序你知道嗎的文章就介紹到這了,更多相關try-catch-finally執行順序內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com