Java 例外處理 (Exception Handling)
例外處理用來處理程式執行時發生的錯誤,讓程式可以優雅地處理異常情況。
基本語法
使用 try-catch 捕捉例外:
try {
// 可能發生例外的程式碼
int result = 10 / 0;
} catch (ArithmeticException e) {
// 處理例外
System.out.println("發生錯誤:" + e.getMessage());
}
try-catch-finally
finally 區塊無論是否發生例外都會執行:
FileReader reader = null;
try {
reader = new FileReader("file.txt");
// 讀取檔案
} catch (FileNotFoundException e) {
System.out.println("找不到檔案");
} finally {
// 一定會執行,用於清理資源
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
多重 catch
try {
int[] arr = {1, 2, 3};
System.out.println(arr[10]);
int result = 10 / 0;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("陣列索引超出範圍");
} catch (ArithmeticException e) {
System.out.println("算術錯誤");
} catch (Exception e) {
System.out.println("其他錯誤");
}
多重例外合併 (Java 7+)
try {
// ...
} catch (IOException | SQLException e) {
System.out.println("I/O 或資料庫錯誤:" + e.getMessage());
}
throw 和 throws
throw:拋出例外
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年齡不能為負數");
}
this.age = age;
}
throws:宣告方法可能拋出的例外
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
// ...
}
// 呼叫時必須處理
try {
readFile("file.txt");
} catch (IOException e) {
e.printStackTrace();
}
更多說明請參考 Java throws。
例外類型
Throwable
├── Error(嚴重錯誤,通常不處理)
│ ├── OutOfMemoryError
│ └── StackOverflowError
└── Exception
├── RuntimeException(非受檢例外)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ ├── ArithmeticException
│ └── IllegalArgumentException
└── IOException(受檢例外)
└── FileNotFoundException
受檢例外 vs 非受檢例外
| 類型 | 說明 | 處理 |
|---|---|---|
| 受檢例外 (Checked) | 編譯時期檢查 | 必須 try-catch 或 throws |
| 非受檢例外 (Unchecked) | 執行時期例外 | 可選擇處理 |
// 受檢例外:必須處理
public void readFile() throws IOException {
FileReader reader = new FileReader("file.txt");
}
// 非受檢例外:可以不處理(但會導致程式中斷)
public void divide(int a, int b) {
int result = a / b; // 可能拋出 ArithmeticException
}
try-with-resources (Java 7+)
自動關閉資源:
try (FileReader reader = new FileReader("file.txt");
BufferedReader br = new BufferedReader(reader)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} // 自動關閉 reader 和 br
更多說明請參考 Java try-with-resources。
常見例外
| 例外 | 說明 |
|---|---|
| NullPointerException | 存取 null 物件 |
| ArrayIndexOutOfBoundsException | 陣列索引超出範圍 |
| ArithmeticException | 算術錯誤(如除以零) |
| NumberFormatException | 數字格式錯誤 |
| ClassCastException | 型別轉換錯誤 |
| IllegalArgumentException | 非法參數 |
| IOException | I/O 錯誤 |
| FileNotFoundException | 找不到檔案 |
更多說明請參考 Java 常見例外。
自訂例外
public class InsufficientBalanceException extends Exception {
private double balance;
private double amount;
public InsufficientBalanceException(double balance, double amount) {
super("餘額不足:餘額 " + balance + ",嘗試提領 " + amount);
this.balance = balance;
this.amount = amount;
}
public double getBalance() {
return balance;
}
public double getAmount() {
return amount;
}
}
// 使用
public void withdraw(double amount) throws InsufficientBalanceException {
if (amount > balance) {
throw new InsufficientBalanceException(balance, amount);
}
balance -= amount;
}
更多說明請參考 Java 自訂例外。
最佳實踐
- 具體的例外:捕捉具體的例外,而不是 Exception
- 有意義的訊息:提供有用的錯誤訊息
- 不要忽略例外:至少要記錄
- 早拋出、晚捕捉:盡早驗證,在適當的層級處理
// 不好
try {
// ...
} catch (Exception e) {
// 忽略
}
// 好
try {
// ...
} catch (FileNotFoundException e) {
logger.error("找不到設定檔", e);
throw new ConfigurationException("無法載入設定", e);
}