1. 程式人生 > >Java核心技術36篇③——異常處理機制

Java核心技術36篇③——異常處理機制

[toc]

Java語言在設計之初就提供了相對完善的異常處理機制,大大提高了程式的可靠性。

異常的分類

我們編寫的程式都會經過編譯、執行這兩個階段,在這兩個階段都會出現異常。Java將這兩個階段的異常分別稱為Checked異常和Runtime異常:

  • checked異常:在編譯階段被強制處理的異常(IDE自動提示的異常)
  • Runtime異常:在執行階段出現的異常,這些異常是非強制處理的(也有稱之為非checked異常)

異常類的結構體系

瘋狂Java講義

圖片中RuntimeException類的子類全部為Runtime異常,而繼承至Exception的其他子類為checked異常

圖片中還有另一個分支ErrorError錯誤與虛擬機器相關(OutOfMemoryError之類的),大部分的Error錯誤會導致程式或JVM處於非正常、不可恢復的狀態,因此沒有捕獲的必要。

異常處理機制

當程式執行期間出現了意外情況,系統會自動生成一個Exception物件來通過程式。從而將“業務實現程式碼”和“錯誤處理程式碼”分離,提高程式的可讀性

Java的異常處理機制主要依賴於try、catch、finally、throw、throws五個關鍵字。

try...catch...finally

把程式的業務實現程式碼放在try塊中,異常處理邏輯放在catch塊中進行處理。

兩個基本概念

  • 丟擲異常:執行try塊裡的業務實現程式碼時出現異常,系統將自動生成一個異常物件,並將其提交給執行時環境

  • 捕獲異常:當執行時環境接收到異常物件時,會自上而下依次判斷該異常物件是否是catch塊後異常類或其子類的例項。如果找到合適的catch塊,則把該異常物件交給catch塊處理(在程式進入catch塊時,賦值於catch塊的形參)。否則,將終止執行時環境並退出程式。

多異常捕獲

  • 捕獲多種型別的異常時,使用“|”將其隔開。
  • 捕獲的多種型別的異常變數是不可變的的(隱式的final修飾)

物理資源的兩種回收方式

Java的垃圾回收機制只能回收堆記憶體中的物件所佔用的資源,不會回收任何物理資源

物理資源像資料庫連線、網路連線、IO操作等都需要顯示回收,顯示回收的兩種方式為新增finally塊或使用自動關閉資源的try語句

finally塊的使用規則

  • 除非在try、catch塊中呼叫了退出虛擬機器的方法(System.exit(0)),否則無論try、catch塊中出現什麼情況,異常處理的finally塊總會被執行
  • finally塊中使用了returnthrow語句,方法最終將得到finally塊中的returnthrow的結果,無論try、catch塊中是否有returnthrow語句

自動關閉回收資源

//()中是可關閉的資源的宣告
//這些資源類必須實現AutoCloseable或Closeable介面,從而實現close()方法
try(BufferReader reader=new BufferReader(...)){
    //do something
}
複製程式碼
//Closeable是AutoCloseable的子介面,只包含close一個方法
//區別是Closeable中的close丟擲IOException異常,而AutoCloseable丟擲Exception異常
public interface Closeable extends AutoCloseable {
    public void close() throws IOException;
}
複製程式碼

throws宣告丟擲異常的規則

當前方法不知道如何處理該型別的異常,應該將異常向上級呼叫者丟擲。直到main方法也無法處理時,該異常將交由jvm處理,jvm的處理方式是——列印異常的StackTrace資訊,並中止程式執行。

  • throws宣告丟擲異常只能在方法簽名中使用
  • 可以丟擲多個異常類並以","號隔開
  • 子類方法宣告丟擲的異常型別應該是父類方法宣告丟擲的異常型別的子類或相同,並且異常型別的數量不能比父類的多

throw主動丟擲異常物件

有一類異常大多數是根據業務需求來決定的,由於與業務需求不符合而產生的異常,必須由開發人員來決定丟擲

throw new IllegalArgumentException("非法引數");
複製程式碼

異常處理的原則

  • 捕獲體現程式碼邏輯相關的特定異常,不要捕獲像Exception這樣的通用異常。

    程式除了被計算機執行之外最多的就是被程式設計師閱讀的,所以我們有義務將自己的程式碼體現出儘量多的資訊。

  • 所有父類異常的catch塊都應該排在子類異常的catch塊之後(先處理小異常,再處理大異常),否則將出現編譯錯誤。

  • 儘量避免在finally塊中使用returnthrow語句,這樣導致try、catch塊中的終止語句失效,進而影響業務邏輯。

  • 不要忽略異常,忽略異常可能導致非常難以診斷的情況出現。

一些部落格或文件