在 Java 程式執行過程中,異常是指打斷正常指令流程的事件。常見場景包含:檔案找不到、網路連線中斷、除以零、陣列索引越界、空指標操作、類型轉換失敗等。若不加處理,異常會導致程式終止運行。
異常處理如同為程式預設「應急預案」。當運行時發生異常,JVM 會依照預先定義的 try-catch-finally 區塊進行處理,處理完畢後程式可繼續執行後續邏輯,而非直接崩潰。
所有錯誤與異常的共同祖先,下分兩大分支:
OutOfMemoryError、StackOverflowError、類載入失敗。應用層無法恢復,亦不應嘗試捕獲,僅能記錄日誌並安全退出。繼承自 RuntimeException,編譯器不強制要求捕獲或拋出。常見範例:NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException。通常源於程式邏輯錯誤,應透過防禦性程式設計避免。
除 RuntimeException 以外的 Exception 子類。編譯器強制要求在方法簽名中用 throws 聲明,或在 try-catch 中捕獲處理。典型代表:IOException、SQLException、ClassNotFoundException。代表外部資源不可控風險,必須顯式處理。
int[] nums = {1, 2, 3, 4};
try {
System.out.println(nums[4]); // 索引 4 不存在
System.out.println("這行不會執行");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("陣列越界錯誤:" + e.getMessage());
}
System.out.println("異常處理後程式繼續執行");
輸出:
陣列越界錯誤:Index 4 out of bounds for length 4 異常處理後程式繼續執行
Scanner sc = new Scanner(System.in);
System.out.print("請輸入被除數:");
int dividend = sc.nextInt();
System.out.print("請輸入除數:");
int divisor = sc.nextInt();
try {
int result = dividend / divisor;
System.out.println("運算結果:" + result);
} catch (ArithmeticException e) {
System.out.println("算術錯誤:除數不能為零");
}
一段程式碼可能拋出多種異常,可串接多個 catch 區塊分別處理。關鍵規則:子類異常必須寫在父類之前。若父類 Exception 放在最前面,所有子類異常都會被它攔截,導致後續 catch 永遠無法執行。
try {
// 可能拋出 IOException、SQLException、Exception
} catch (IOException e) {
// 處理 IO 異常
} catch (SQLException e) {
// 處理 SQL 異常
} catch (Exception e) {
// 兜底處理其他異常
}
throw:在方法內部主動拋出異常實例,用於業務邏輯校驗失敗時通知調用方。throws:在方法簽名聲明可能拋出的受檢異常,將處理責任上傳給調用者。public void setGender(String gender) throws IllegalArgumentException {
if (!"男".equals(gender) && !"女".equals(gender)) {
throw new IllegalArgumentException("性別必須為 '男' 或 '女'");
}
this.gender = gender;
}
try-with-resources 自動管理。RuntimeException 或 Exception,並提供建構子保留原始堆疊追蹤。e.getMessage()。