本文原始碼:GitHub·點這裡 || GitEE·點這裡
一、異常簡介
優秀的程式程式碼,都在追求高效,安全,和低錯誤率,但是程式中的異常是無法避免的,降低異常出現的頻率是關鍵,異常出現如何處理是另一個重要方面,Java體系中異常框架對於系統開發是十分重要的。
面對系統異常時,不要慌亂,異常雖然是錯誤,也是系統發出的訊息,標識系統的缺陷和需要改進的地方。
二、API體系
Java的API中已經定義許多異常類,分為兩大類,錯誤Error和異常Exception,Throwable作為所有異常的超類,如圖:
Error:一般為底層的不可恢復的類,一般此類錯誤都比較嚴重,JVM將終止其執行的執行緒;
- VirtualMachineError:虛擬機器執行錯誤;
- OutOfMemoryError:記憶體溢位;
Exception:程式本身可以捕獲並且可以預處理的異常,例如捕獲或者丟擲;
- RuntimeException:執行時異常;
- CheckException:已檢查異常,編譯階段必須處理;
幾個經典的常見的RunTimeException如下:空指標NullPointerException;陣列下標越界ArrayIndexoutofBoundsException等。
三、異常處理
Java異常處理關鍵字,分別是:try、catch、finally、throw、throws。
應該在合適的位置處理異常,異常的處理準則如下:誰知情誰處理,誰負責誰處理,誰導致誰處理。
1、丟擲異常
即異常在當前流程下不處理,一種是直接通過方法傳遞給呼叫者,throws關鍵字是用於在方法宣告上宣告丟擲異常型別的,並且一次可以宣告丟擲多種型別的異常。throw關鍵字是用於方法的內部丟擲一個異常物件,常在業務校驗時丟擲提示。
需要特別說明的一點,在Spring框架中,事務觸發多數是以是否丟擲異常為標識來處理的,如果方法在事務控制內,方法內異常捕獲但是最終沒有丟擲,那該事務則無效。
2、捕獲異常
通常捕獲異常會使用try-catch-finally關鍵字三連操作:
Try嘗試捕獲異常:
如果語句依次執行結束,則跳過catch,在存在finally程式碼塊時,則執行否則執行後續流程;
如果捕獲異常,則匹配catch中的型別,如果沒有與之匹配的catch型別,則該異常交給JVM處理,finally程式碼會被執行,流程之後的程式碼不會被執行;
如果捕獲異常且存在相匹配的catch型別,則跳到catch程式碼塊執行,finally程式碼會被執行,執行完finally程式碼塊之後繼續執行後續程式碼;
Catch匹配可能出現的異常型別,並在其中做補償處理,例如出現異常情況,需要更新一個異常狀態等,如果沒有catch塊,後必須跟finally塊,處理資源釋放;
Finally無論是否捕獲異常,finally程式碼會被執行,也是面試中常見的異常問題之一,例如在finally程式碼塊return,或者修改返回值等,主要涉及到值傳遞和引用傳遞方面。
3、異常日誌
複雜的業務系統必備功能,異常日誌體系,用來分析執行問題,作為系統不斷優化的核心依據,通常會記錄如下幾塊:
- 異常型別:分析異常發生的關鍵原因;
- 異常資訊:通常會簡單記錄e.getMsg輸出的內容;
- 異常位置:快速定位異常發生的位置[類.方法];
- 業務引數:特定業務引數場景才能復現的問題;
- 時間節點:有的併發問題是在特定時間段出現;
異常日誌記錄下來之後,還會定期進行任務分析,不斷發現系統容易出問題的地方,然後再不斷的改進和優化。
4、熔斷降級
在微服務架構系統下,某個服務故障或者異常,觸發熔斷該服務,避免引發整個微服務鏈路異常,防止整個系統服務的雪崩。以此緩解伺服器資源的的壓力,以保證核心業務的正常執行。
四、原始碼地址
GitHub·地址
https://github.com/cicadasmile
GitEE·地址
https://gitee.com/cicadasmile