在 Java 開發中,雖然內建的異常類別已能涵蓋大多數常見錯誤情境,但實際專案往往需要表達特定業務邏輯的錯誤狀態。此時建立自訂異常類別便顯得尤為重要。本文將詳細說明如何透過繼承 Exception 類別來建立屬於自己的異常體系,並示範如何為異常添加建構子、資料欄位與存取方法,使其攜帶更豐富的診斷資訊。
Java 的標準異常階層雖然完善,但無法預知所有程式庫或應用程式特有的錯誤類型。當你開發一個供他人使用的類別庫時,拋出標準異常往往缺乏業務語意,導致呼叫端難以精準捕獲並處理特定錯誤。自訂異常能讓你:
InsufficientBalanceException、InvalidOrderStateException)建立自訂異常的核心在於 extends Exception。這表示新類別「是一個」Exception,擁有其所有功能,並可擴充屬於自己的行為。最簡單的自訂異常只需提供兩個標準建構子:
public class MyException extends Exception {
public MyException() {}
public MyException(String msg) {
super(msg); // 明確呼叫父類別帶字串參數的建構子
}
}
關鍵點解析:
super();但慣例上仍建議明確寫出。super(msg) 將錯誤訊息傳給父類別,讓 getMessage() 能正常運作。以下完整程式展示如何在方法中拋出 MyException,並在 main 中捕獲處理:
public class Inheriting {
public static void f() throws MyException {
System.out.println("Throwing MyException from f()");
throw new MyException();
}
public static void g() throws MyException {
System.out.println("Throwing MyException from g()");
throw new MyException("Originated in g()");
}
public static void main(String[] args) {
try { f(); } catch (MyException e) { e.printStackTrace(); }
try { g(); } catch (MyException e) { e.printStackTrace(); }
}
}
執行輸出:
Throwing MyException from f()
MyException
at Inheriting.f(Inheriting.java:16)
at Inheriting.main(Inheriting.java:24)
Throwing MyException from g()
MyException: Originated in g()
at Inheriting.g(Inheriting.java:20)
at Inheriting.main(Inheriting.java:29)
觀察可知:無訊息建構子拋出的異常堆疊追蹤缺乏詳細說明,而帶訊息版本則清晰標示錯誤來源。
異常本質上也是物件,因此可以像一般類別一樣擁有欄位、方法與多載建構子。以下範例加入整數欄位 i 及對應的存取方法:
public class MyException2 extends Exception {
private int i; // 額外的錯誤碼或狀態值
public MyException2() {}
public MyException2(String msg) { super(msg); }
public MyException2(String msg, int x) {
super(msg);
i = x;
}
public int val() { return i; } // 提供讀取額外資料的方法
}
使用方式:
public static void h() throws MyException2 {
throw new MyException2("Originated in h()", 47);
}
// 捕獲時可取得額外資訊
try { h(); }
catch (MyException2 e) {
e.printStackTrace();
System.out.println("e.val() = " + e.val()); // 輸出 47
}
有時只需一個標記性質的異常類型,完全依賴編譯器自動產生的預設建構子即可:
class SimpleException extends Exception { }
此時無 String 參數建構子,但對於單純用於型別判斷的情境已足夠。
Exception 結尾,清楚表達錯誤性質。Throwable cause)三種,符合 Java 異常鏈慣例。final。掌握自訂異常的建立與擴充技巧,能讓你的程式碼錯誤處理更具表達力、可維護性與專業度。