一、異常體系架構
1.1 體系圖解
1.2 Exception & Error
Exception
表示程式可以處理的異常情況,通常是由於程式邏輯錯誤或執行時問題引起的,比如NullPointException、IOException等。這些異常是設計用來被程式捕獲,並採取相應的恢復措施來繼續執行,即具有可恢復性。
Error
表示系統級的錯誤,通常是是虛擬機器無法恢復的錯誤,如OutOfMemoryError、StackOverflowError等。這些錯誤通常不期望程式能夠處理,即不建議使用try...catch進行捕獲處理,因為他們通常表明JVM本身遇到了嚴重問題,不具有可恢復性。
對於Error類及其子類的嚴重錯誤,通常由以下幾個處理原則:
- 不推薦捕獲處理:Error類及其子類通常表示程式無法繼續正常執行的情況。捕獲這些異常通常沒有意義,因為它們表示的問題是程式無法控制和恢復的。例如,如果程式遇到了0ut0fMemoryError即使捕獲了這個異常,程式也無法繼續執行,因為記憶體已經耗盡。
- 程式中止:大多數Error類異常都是程式執行時的嚴重問題,它們通常會導致程式終止。捕獲這些異常可能會導致程式處於一個不確定的狀態,這可能比程式直接終止更危險。
- 資源清理:儘管不推薦捕獲Error類異常,但在某些情況下,你可能想要在程式終止之前進行一些資源清理工作。在這種情況下,可以在catch塊中新增資源釋放的程式碼,但通常不會嘗試恢復程式的正常執行。
- 日誌記錄:在捕獲Error類異常時,一個常見的做法是記錄詳細的錯誤資訊,這對於事後分析和除錯是有幫助的。這可以透過在catch塊中新增日誌記錄程式碼來實現。
- 使用者友好的反饋:如果程式是面向使用者的,那麼在捕獲Error類異常時,可以向使用者提供一些友好的錯誤資訊,而不是讓程式突然崩潰,這樣可以提高使用者體驗。
- 程式設計:在設計程式時,應該儘量避免可能導致Error類異常的情況。例如,透過合理的資源管理和錯誤處理來減少0ut0fMemoryError的發生。
Simple Conclusion
總結來說,Exception是程式可以並且應該處理的異常,而Error是程式通常無法處理的嚴重錯誤。在實際程式設計中,我們通常會關注如何處理Exception,而對於Error,我們更多的是透過程式碼最佳化和資源管理來儘量避免它們的發生。
1.3 Checked Exceptions & UnChecked Exceptions
Checked Exceptions
即檢查型異常,指那些在編譯時必須被處理的異常。它們通常是由於外部因素引起的,比如檔案找不到、網路問題等。這類異常的存在有助於提高程式碼的健壯性,因為編譯器會強制開發者處理這些潛在的錯誤情況——必須在編譯時處理,要麼透過try-catch語句捕獲處理,要麼透過方法簽名中的throws關鍵字宣告丟擲。Exception的子類(RuntimeException及其子類除外)都是檢查型異常。
Unchecked Exceptions
即非檢查型異常,指那些在編譯時不需要被處理的異常。它們通常是由於程式內部邏輯錯誤引起的比如陣列越界、空指標引用等。這類異常通常表示程式中的錯誤,這些錯誤應該在開發階段被修復,而不是在執行時透過異常處理機制來處理,因此編譯器也並不會強制開發者捕獲或宣告丟擲這些異常。RuntimeException及其子類屬於非檢查型異常,當然,Error及其子類也歸屬於非檢查型異常。
Simple Compare
二、異常的宣告、丟擲與捕獲
2.1 宣告異常
對於檢查型異常,可以透過throws關鍵字宣告,即在方法簽名中宣告,表示該方法可能會丟擲異常。此時如果丟擲了異常,那麼方法呼叫者需要自己處理或繼續宣告和丟擲。當你的方法無法處理某種異常,或者你希望呼叫者來處理這種異常時,你可以選擇在方法簽名中使用throws宣告異常。
2.2 丟擲異常
丟擲異常只會發生在方法內部,使用throw關鍵字丟擲一個異常例項,由於異常例項是一個物件,所以丟擲時都是 throw new xxxException 。當你的程式碼到達一個無法正常繼續執行的狀態,或者需要通知方法的呼叫者出現了一個異常情況時,就可以在程式碼中使用throw關鍵字來丟擲一個異常。
2.3 捕獲處理異常
如果想要捕獲並處理異常,是的程式以期望的步驟執行,就需要使用try-catch進行異常的捕獲。try程式碼塊中放可能產生異常的程式碼,catch中進行異常的處理,可以選擇丟擲——即使用throw關鍵字,也可以選擇記錄異常日誌,進行異常處理等。
2.4 throws、throw、try-catch、try-catch-finally、try-finally
使用了throws宣告異常後,方法程式碼塊中可以不使用throw手動丟擲異常,如果某句程式碼產生了宣告的異常,會自己丟擲。當然也可以手動丟擲所宣告的異常,常用於自定義異常。
使用了throws宣告異常後,是否還需要try-catch去捕獲?如果在catch程式碼塊中,並沒有手動使用throw去丟擲異常,那麼這時候throws的宣告是多餘的。即方法呼叫者永遠無法知道發生了什麼異常,因為異常已經被捕獲處理。
使用try-catch的時候,如果catch中宣告的異常型別(一個try可以多個catch)沒有匹配到try塊中產生的異常,異常仍然會向上傳播。catch塊中常常是處理異常,列印異常日誌資訊等,一般不做異常的丟擲。如果做了異常的丟擲,那我們希望要在方法簽名上宣告該異常。
使用try-catch-finally的時候,即使catch中沒有捕獲到發生的異常,finally中的程式碼塊始終會被執行。
使用try-finaly的時候,如果發生了異常,異常不會被捕獲,會向上傳播。