Java異常系列之finally的真正執行時機
異常是Java核心中非常重要的一個概念,但卻很容易被大家忽略,這個系列我們會深入講一下這個話題。學完這個系列,相信會讓你對異常體系以及異常的各種使用場景,瞭如指掌,成為你職業進階的必備技能。
名稱 | 狀態 |
---|---|
finally 的真正執行時機 | 已完成 |
try-with-resources 語句 | 已完成 |
Java 異常體系 | 創作中... |
catch 中的異常引數 | 創作中... |
Java 異常鏈 | 創作中... |
SpringMVC 中的異常處理 | 創作中... |
自定義 SpringMVC 的異常處理鏈 | 創作中... |
在之前的 Java語法糖 : 使用 try-with-resources 語句安全地釋放資源 一文中,我們介紹瞭如何通過 try-with-resources 語句來代替醜陋的 finally 塊。
但 try-with-resources 語句僅僅適用於自動關閉資源,有些場景下我們需要無論一段程式碼發生異常與否,都需要執行另外一段程式碼,這個時候就需要使用 finally 塊了。
如果有人問你 發生異常以後 finally 塊的內容什麼時候會執行?你也許會毫不猶豫地回答:當然是執行完 catch 塊的內容以後執行了。
但有時候你的回答也許沒法這麼幹脆,比如下面這個例子。
當在 catch 塊和 finally 塊同時 return
的時候,到底會 return
什麼呢?
public static int testFinally1() { try { Integer.parseInt("exception here"); } catch (Exception e) { System.out.println("catch block 1"); return 11; } finally { System.out.println("finally block 1"); return 12; } } 複製程式碼
事實上,即使 catch 塊有 return
語句, finally 塊必然執行的邏輯還是成立的。上面的方法, return
的是 12
。先輸出 catch block 1
,然後輸出 finally block 1
,最後返回 12
。
不知道你發現規律沒有,下面再舉個例子你就更清晰了。
public static int testFinally3() { try { System.out.println("start"); Integer.parseInt("testFinally3"); System.out.println("never run"); } catch (Exception e) { System.out.println("catch block 3"); return iamReturn(); } finally { System.out.println("finally block 3"); } return 31; } public static int iamReturn() { System.out.println("return block"); return 666; } 複製程式碼
思考一下執行這個方法會分別輸出和返回什麼?
先彆著急看答案,根據我們之前發現的規律, finally 塊必然執行,而 catch 塊的非 return
部分需要在 finally 塊之前執行。那麼最終返回的應該是 666
。
答案確實如此。下面是控制檯輸出的順序:
start catch block 3 return block finally block 3 複製程式碼
由此,我們可以總結 finally 塊的真正執行時機了:
- finally 塊必然執行,不論發生異常與否,也不論在 finally 之前是否有
return
。 - 不管在 try 塊中還是在 catch 塊中包含 return,finally 塊總是在
return
之前執行。 - 如果 finally 塊中有
return
,那麼 try 塊和 catch 塊中的return
就沒有執行機會了。
如果你真的理解了finally 塊的真正執行時機,那麼請思考一下,下面程式的返回值是 21
還是 22
,歡迎留言討論。
public static int testFinally2() { try { System.out.println("start"); return 21; } catch (Exception e) { System.out.println("catch block 2"); } finally { System.out.println("finally block 2"); } return 22; } 複製程式碼
