異常處理是 Java 程式健壯性的基石。本文從基礎語法進階到異常鏈、stack trace 分析、finalize 陷阱等高階主題,提供生產級最佳實踐。
// 拋出異常
public void risky() throws IOException {
throw new IOException("磁盤錯誤");
}
// 捕獲處理
try {
risky();
} catch (IOException e) {
e.printStackTrace(); // 或記錄日誌
// 恢復邏輯或轉換異常
}
// 檢查型異常 (必須處理)
public class BusinessException extends Exception {
public BusinessException(String msg) { super(msg); }
public BusinessException(String msg, Throwable cause) { super(msg, cause); }
}
// 運行時異常 (可選處理)
public class SystemException extends RuntimeException {
public SystemException(String msg, Throwable cause) { super(msg, cause); }
}
原則:可恢復業務錯誤用檢查型異常,編程錯誤/系統級故障用運行時異常。
try {
throw new Exception("測試");
} catch (Exception e) {
// 方式一:打印標準堆棧
e.printStackTrace();
// 方式二:程序化訪問 (Java 1.4+)
StackTraceElement[] elements = e.getStackTrace();
for (StackTraceElement el : elements) {
System.out.printf("%s.%s(%s:%d)%n",
el.getClassName(), el.getMethodName(),
el.getFileName(), el.getLineNumber());
}
}
關鍵洞察:堆棧頂部是拋出點,底部是調用入口 (main)。getStackTrace() 返回可序列化數組,便於遠程傳輸與日誌系統集成。
// ❌ 錯誤:丟失原始堆棧
catch (Exception e) { throw e; }
// ✅ 正確:保留原始堆棧 (Java 7+ 自動保留)
// 但若需重置堆棧為當前位置:
catch (Exception e) { throw (Exception) e.fillInStackTrace(); }
try {
a();
} catch (AException e) {
BException be = new BException("業務處理失敗");
be.initCause(e); // 關鍵:建立因果鏈
throw be;
}
輸出包含 Caused by: 鏈路,完整保留 A→B→C 的錯誤傳播路徑,極大提升排查效率。
finalize() 釋放資源 (不可預測、延遲、可能不執行)try-with-resources (Java 7+) 或 try-finally 確定性釋放AutoCloseable 接口讓資源支持自動關閉// 標準資源管理模式
public class Resource implements AutoCloseable {
@Override public void close() { /* 釋放邏輯 */ }
}
// 使用
try (Resource r = new Resource()) {
r.use();
} // 編譯器自動插入 finally 調用 close()
// Finalizer Guardian 模式
public class Parent {
private final Object guardian = new Object() {
@Override protected void finalize() throws Throwable {
// 父類關鍵清理邏輯,即使子類 finalize 失敗也會執行
cleanupNativeResources();
}
};
}
catch (IOException e) 而非 catch (Exception e)throw new BizEx(msg, cause)