異常處理是 Java 程式健壯性的基石。本文從異常定義、分類體系、五大關鍵字(try/catch/throw/throws/finally)語法、執行流程到常見陷阱,為初學者建立清晰的異常處理認知框架。
異常:程式執行期間發生的非預期事件(錯誤、中斷正常流程)。Java 用物件封裝異常資訊,發生時建立異常物件並「拋出」(throw),呼叫鏈向上傳遞直到被「捕捉」(catch)或導致執行緒終止。
NullPointerException)、超出執行環境限制(StackOverflowError)。throw new IllegalArgumentException("參數非法"),用於報告業務邏輯錯誤。
java.lang.Throwable
├── java.lang.Error // 嚴重錯誤,不可恢復(OOM, StackOverflow)
└── java.lang.Exception // 應用層異常,可捕捉處理
├── java.lang.RuntimeException // 非受檢異常(編譯器不強制處理)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ └── IllegalArgumentException
└── 其他 Exception 子類 // 受檢異常(必須 try-catch 或 throws)
├── IOException
├── SQLException
└── ClassNotFoundException
try {
// 監控區塊:可能拋出異常的代碼
riskyOperation();
} catch (ExceptionType1 e) {
// 處理 ExceptionType1 及其子類
handleType1(e);
} catch (ExceptionType2 e) {
// 處理 ExceptionType2
handleType2(e);
} finally {
// 清理區塊:無論是否異常、是否 return,皆會執行(極少數例外:System.exit, 死循環)
cleanupResources(); // 關閉流、釋放鎖、關閉連線
}
try 後必須跟至少一個 catch 或 finally。catch 子句按順序匹配,**子類異常必須寫在父類之前**,否則編譯錯誤(unreachable catch)。finally 即使在 catch 中 return 也會執行;但 System.exit(0) 或 JVM 崩潰則不執行。throw 用於方法內部主動拋出異常物件;throws 用於方法簽名聲明可能拋出的受檢異常。
正常情況:
try 區塊依序執行 → 跳過所有 catch → 執行 finally → 繼續後續代碼
異常情況(假設第 2 行拋出 IOException):
try 第 1 行 → 第 2 行拋出 → 跳過 try 剩餘 → 匹配 catch (IOException) → 執行該 catch → 執行 finally → 繼續後續
異常未捕捉:
try 拋出 Exception → 無匹配 catch → 執行 finally → 異常向上拋給呼叫者
public int test() {
try { return 1; }
finally { return 2; } // 方法回傳 2,原本的異常或 return 1 被吞沒!
}
鐵律:finally 區塊絕對不要使用 return/throw/break/continue。
// 錯誤:若 read() 拋出異常,close() 不會執行
FileInputStream fis = new FileInputStream("a.txt");
try { fis.read(); } catch (IOException e) { }
fis.close();
// 自動關閉實作 AutoCloseable 的資源,順序反向
try (FileInputStream fis = new FileInputStream("a.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
bis.read();
} catch (IOException e) {
log.error("讀取失敗", e);
}
// 編譯器自動生成 finally { bis.close(); fis.close(); }
// 錯誤:新異常未保留原始 cause
catch (SQLException e) { throw new RuntimeException("DB錯誤"); }
// 正確:保留因果鏈
catch (SQLException e) { throw new BizException("DB錯誤", e); }
// Java 7+ 多重捕捉(聯集類型)
try { ... }
catch (IOException | SQLException e) {
log.error("IO/DB 錯誤", e);
throw new DataAccessException(e);
}
異常處理的核心是「失敗快速、資源不洩漏、堆疊可追蹤」。掌握 try-with-resources、正確使用 finally、保留因果鏈、合理選擇異常類型,能讓你的 Java 程式在異常情況下依然穩健可控。