在 Java 中,異常被視為物件,所有系統定義的編譯期與運行期異常均由 JVM 自動拋出,稱為標準異常。但實際開發中,Java 強制要求應用程式完整處理異常,提供友善提示或修正後繼續執行。對於自訂異常或業務專屬異常,必須透過 throw 與 throws 兩大關鍵字來聲明與拋出。
語法: throw new ExceptionType("錯誤訊息");
位置: 方法體內部,表示當前方法主動拋出一個具體的異常物件,由呼叫端或上層捕獲處理。
範例:
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年齡必須在 0~150 之間");
}
this.age = age;
}
此處主動建構 IllegalArgumentException 實例並拋出,屬於運行時異常,編譯器不強制捕獲。
語法: 修飾符 返回類型 方法名(參數) throws ExceptionType1, ExceptionType2 { ... }
位置: 方法簽名處,聲明該方法「可能」拋出的受檢異常,將處理責任推給呼叫者。
範例:
public void readConfig(String path) throws IOException, ParseException {
FileInputStream fis = new FileInputStream(path);
// ... 解析邏輯可能拋出 IOException、ParseException
}
呼叫端必須用 try-catch 捕獲或繼續 throws 向上傳遞。
| 維度 | throw | throws |
|---|---|---|
| 作用對象 | 異常實例 (new Exception()) | 異常類別 (Exception.class) |
| 出現位置 | 方法體內部語句 | 方法宣告簽名 |
| 語意 | 「我現在拋出這個錯誤」 | 「這個方法可能會出錯,你們注意」 |
| 處理責任 | 由上層呼叫鏈捕獲 | 強制呼叫端處理或繼續拋出 |
| 適用異常 | 所有 Throwable 子類 | 主要針對受檢異常 |
throws Exception 就萬事大吉。實則掩蓋具體錯誤類型,導致呼叫端無法精準處理。throws SQLException, IOException),避免使用父類 Exception。throw 封裝業務異常(如 throw new BizException("庫存不足", e)),上層用 throws 聲明,最上層統一攔截轉為友善回應。throw 是動作,throws 是契約。善用兩者結合,能構建清晰、可維護的異常處理體系,讓錯誤流向可控、語意明確。