
try-catch 捕獲或 throws 拋出(如 IOException),強制 API 使用者處理。RuntimeException 及其子類(如 NullPointerException、ArithmeticException),通常為程式邏輯錯誤,無法合理復原。呼叫者能夠合理處理 → 受檢例外(如檔案不存在、網路中斷)
呼叫者無法處理/屬於程式錯誤 → 非受檢例外(如參數驗證失敗、除零)
「當前能妥善處理 → 捕獲處理;無法處理 → 明確拋出,讓上層決定」
try {
File file = new File("path");
FileInputStream fis = new FileInputStream(file);
String s = "inside"; // 可能拋出例外前就宣告,但編譯器不保證執行到這行
} catch (FileNotFoundException e) {
System.out.println(s); // 編譯錯誤:s 可能未初始化
}
原因:編譯器無法確認 s 宣告前是否已拋出例外。解法:在 try 外宣告並初始化為 null。
Integer.parseInt(null); // NumberFormatException Double.parseDouble(null); // NullPointerException (JDK 7 前)
早期 JDK 實作不一致,屬實作細節差異。現代 JDK (7+) 統一拋出 NumberFormatException。無需深究,統一捕獲 NumberFormatException 即可。
public void setAge(int age) {
if (age < 0 || age > 150)
throw new IllegalArgumentException("年齡必須在 0-150 之間: " + age);
this.age = age;
}
常用:IllegalArgumentException、IllegalStateException、IndexOutOfBoundsException、UnsupportedOperationException。
catch (IOException | SQLException ex) { ... }catch (Exception e)(謹慎使用,避免吞沒錯誤)Exception 後用 instanceof 判斷分派可以。若建構子拋出例外,物件不會被建立,記憶體由 GC 回收。適用於驗證建構參數有效性。
finally {
try {
cleanup();
} catch (IOException e) {
log.error("清理失敗", e); // 建議封裝成方法提升可讀性
}
}
注意:若 try 與 finally 都拋出例外,try 的例外會被 finally 的例外覆蓋遺失(Java 7+ 可用 addSuppressed 保留)。
可以,但極度不建議。finally 的 return 會覆蓋 try/catch 的回傳值,導致極難除錯的邏輯錯誤。
try { ... } catch (Exception e) { e.printStackTrace(); } // 只印堆疊,無實質處理
原因:IDE 快速修復產生樣板碼、趕工期、不確定如何處理。
後果:錯誤被隱藏、難以追蹤、系統狀態不一致。
原則:無法處理 → 拋出;能處理 → 完整處理(記錄、重試、補償、轉換為業務例外)。
finally 專為資源清理設計,勿濫用控制流程原文連結:ProgramCreek 翻譯版