異常處理是 Java 核心機制,但許多開發者僅停留在「會用 try-catch」層級。本文將異常處理品質分為三級——好、壞、醜,並提供改善建議。
Exception 但非 RuntimeException。必須捕獲或拋出(throws),適用預期可恢復的情況(如 IO 錯誤)。Error(系統級嚴重錯誤)與 RuntimeException(程式邏輯錯誤,如空指標、陣列越界)。不強制處理,應透過程式碼修正預防。方法簽名中 throws 僅需宣告受檢異常;Error 與 RuntimeException 不應出現在 throws 中。
利用 throws 將可能的失敗模式納入方法契約,呼叫端可針對性處理:
public FileInputStream(String name) throws FileNotFoundException
try {
FileInputStream fis = new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
System.err.println("檔案不存在: " + args[0]);
System.exit(1);
}
優勢:編譯器強制檢查、失敗模式文檔化、支援自訂異常封裝業務錯誤、JDK 1.4+ Logging API 統一記錄。
RuntimeException 子類以逃避 throws,導致呼叫端無感知,錯誤在遠端爆發。try { ... } catch (Throwable t) { t.printStackTrace(); }
吞沒異常、掩蓋根因、阻礙除錯。僅允許在頂層錯誤處理器(配合集中日誌)使用。此外,低記憶體、寫入失敗、演算法錯誤等嚴重異常往往難以優雅恢復,需謹慎評估恢復策略(重試、GC、用戶提示)。
throw new SomeException() 本身可能觸發 OutOfMemoryError,導致原始異常丟失、錯誤資訊扭曲。OutOfMemoryError 非受檢卻常見:記憶體耗盡屬高機率事件,卻不受編譯器強制處理,finally 區塊釋放資源時可能再次觸發 OOM,形成惡性循環。try 區塊,失敗即整體回滾。throws),讓上層決策。