在 Java 語言中,java.lang.Error 為錯誤類基類,java.lang.Exception 為異常類基類,兩者皆繼承自 java.lang.Throwable。因此 Throwable 及其子類實例均可作為 throw 操作對象。
try-catch 或 throws 聲明,可隨時拋出throws 聲明或以 try-catch 捕獲處理// Error 子類 - 無需聲明
public String myMethod() { throw new MyError(); }
// Exception 子類 - 必須聲明
public String myMethod() throws MyException { throw new MyException(); }
JVM 使用方法呼叫堆疊追蹤每個執行緒的方法調用鏈。新方法被調用時,其堆疊幀壓入堆疊頂端;正常返回則彈出。當方法拋出異常,JVM 從當前方法向上搜尋匹配的 catch 區塊;若一路追溯至 main() 仍無處理器,執行緒異常終止,主執行緒則導致應用程式退出,JVM 將原始異常資訊輸出至用戶終端。
public Throwable() { fillInStackTrace(); }
public Throwable(String message) { fillInStackTrace(); detailMessage = message; }
public Throwable(String message, Throwable cause) { fillInStackTrace(); detailMessage = message; this.cause = cause; }
public Throwable(Throwable cause) { fillInStackTrace(); detailMessage = (cause==null ? null : cause.toString()); this.cause = cause; }
關鍵點:
fillInStackTrace() 為 native 方法,捕獲當前執行緒堆疊軌跡cause 欄位預設指向 this,表示未初始化;透過 initCause() 可單次設定detailMessage 保存異常描述訊息private transient Object backtrace; // 原生堆疊軌跡指標 private String detailMessage; // 異常詳細訊息 private Throwable cause = this; // 因果鏈參考 private StackTraceElement[] stackTrace; // 解析後的堆疊元素陣列
initCause() 與 getCause()public synchronized Throwable initCause(Throwable cause) {
if (this.cause != this) throw new IllegalStateException("Can't overwrite cause");
if (cause == this) throw new IllegalArgumentException("Self-causation not permitted");
this.cause = cause;
return this;
}
public Throwable getCause() { return (cause==this ? null : cause); }
設計保證:因果關係只能初始化一次,且不可自我循環引用。
printStackTrace() 多載實作支援 PrintStream、PrintWriter 輸出,同步鎖定輸出流確保線程安全。核心流程:
toString() 表示getOurStackTrace() 返回的堆疊元素陣列printStackTraceAsCause()// 從堆疊尾部向前比較,找出與造成者共用的幀數量
while (m >= 0 && n >= 0 && trace[m].equals(causedTrace[n])) { m--; n--; }
int framesInCommon = trace.length - 1 - m;
// 輸出差異幀,共用部分以 "... N more" 簡略表示
此機制避免重複輸出共同呼叫鏈,提升可讀性。
private synchronized StackTraceElement[] getOurStackTrace() {
if (stackTrace == null) {
int depth = getStackTraceDepth();
stackTrace = new StackTraceElement[depth];
for (int i = 0; i < depth; i++) stackTrace[i] = getStackTraceElement(i);
}
return stackTrace;
}
getStackTraceDepth()、getStackTraceElement(int) 為 native 方法setStackTrace() 允許自訂堆疊軌跡(如遠程異常重組)private synchronized void writeObject(ObjectOutputStream s) throws IOException {
getOurStackTrace(); // 確保堆疊軌跡已初始化
s.defaultWriteObject();
}
實作 Serializable 介面,序列化前強制初始化堆疊軌跡,保證異常物件可跨 JVM 傳遞並保留完整上下文。
Throwable 作為 Java 異常體系根基,封裝了訊息、因果鏈、堆疊軌跡三大核心資訊。其設計精妙在於:
深入理解 Throwable 機制,有助於設計更健壯的異常處理策略、實作自訂異常體系、以及進行分散式追蹤與診斷。