1. 多個 catch:處理不同的例外
在真實的程式中,同一段程式碼可能會拋出不同型別的例外。舉例來說,讀取檔案時可能出現 FileNotFoundException 或 IOException,而在剖析資料時——還可能出現 NumberFormatException。為了正確處理每種情況,Java 可以連續使用多個 catch 區塊。
語法
try {
// 危險操作
} catch (FileNotFoundException e) {
System.out.println("找不到檔案:" + e.getMessage());
} catch (IOException e) {
System.out.println("輸入/輸出錯誤:" + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("數值格式不正確:" + e.getMessage());
}
重點:
catch 區塊必須由較具體排到較一般! 如果一開始就寫 catch (Exception e),其他更具體的區塊將永遠到達不了,編譯器會報錯。
為什麼這很重要?
- 特定處理: 可以針對不同錯誤採取不同反應(例如提示選擇其他檔案或重新輸入)。
- 可讀性: 程式碼更清楚——看得出預期會有什麼錯誤以及如何處理。
2. 具有多個型別的 catch(multi-catch)
有時不同的例外需要相同的處理。比方說,不論是讀檔錯誤或是數字轉換錯誤,你只想輸出錯誤訊息或記錄日誌。
自 Java 7 起,提供了 multi-catch 語法,允許在同一個區塊中合併多個例外型別:
try {
// 危險操作
} catch (IOException | NumberFormatException e) {
System.out.println("處理檔案或數字時發生錯誤:" + e.getMessage());
}
運作方式:
- 透過垂直線(|)列出例外型別。
- 變數 e 會具有這些型別的共同父型別(通常是 Exception)。
- 在區塊內不能重新指定變數 e 的值——它會自動被視為 final。
範例:
try {
BufferedReader reader = new BufferedReader(new FileReader("numbers.txt"));
String line = reader.readLine();
int number = Integer.parseInt(line);
System.out.println("數字:" + number);
reader.close();
} catch (IOException | NumberFormatException e) {
System.out.println("錯誤:" + e.getMessage());
}
3. 例外處理最佳實務
不要吞掉例外
不好:
try {
// 某些危險操作
} catch (Exception e) {
// 什麼都不做!
}
為什麼不好?
空的 catch 區塊會「吞掉」錯誤——你會失去故障原因的資訊,程式將變得難以除錯。
較好: 至少輸出訊息或記錄錯誤。
catch (Exception e) {
e.printStackTrace();
}
如果你無法在此處處理例外——就把它往外拋:
catch (IOException e) {
throw e; // 或是 throw new RuntimeException(e);
}
拋出最具體的例外
當你撰寫自己的方法或 API 時,務必拋出最具體的例外,而不是單純的 Exception 或 RuntimeException。這能讓你的程式碼與介面對其他開發者更清楚。
範例:
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("餘額不足");
}
// ...
}
不要用例外來控制程式流程
例外是為了處理例外情況——也就是在正常執行流程中不應該發生的錯誤。不要把例外用在一般邏輯(例如用來跳出迴圈或檢查條件)。
不好:
try {
while (true) {
String line = reader.readLine();
if (line == null) break;
// 處理每一行
}
} catch (Exception e) {
// 用例外來跳出迴圈——很糟!
}
好:
String line;
while ((line = reader.readLine()) != null) {
// 處理每一行
}
4. 實務範例
範例:針對不同錯誤做不同處理
try {
BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
String line = reader.readLine();
int number = Integer.parseInt(line);
System.out.println("數字:" + number);
reader.close();
} catch (FileNotFoundException e) {
System.out.println("找不到檔案!");
} catch (IOException e) {
System.out.println("讀取檔案時發生錯誤!");
} catch (NumberFormatException e) {
System.out.println("檔案內容不是數字!");
}
範例:multi-catch 進行相同處理
try {
// 某些危險操作
} catch (IOException | NumberFormatException e) {
System.out.println("錯誤:" + e.getMessage());
}
5. 重要細節與常見錯誤
錯誤 №1:catch 區塊順序不正確。 應先寫較具體的例外,然後再寫一般的。否則永遠不會執行到較廣泛的區塊。
錯誤 №2:在 multi-catch 中使用具繼承關係的型別。 例如,catch (IOException | Exception e) 不會通過編譯,因為 IOException 是 Exception 的子類別。
錯誤 №3:嘗試在 multi-catch 中修改變數 e。 在這種情況下 e 會被視為 final——不能重新指派新值。
錯誤 №4:空的 catch 區塊。 忽略錯誤會導致「無聲」的 bug。至少要輸出訊息或記錄例外。
錯誤 №5:一股腦地捕捉所有 Exception。 使用 catch (Exception e) 會掩蓋真正的問題並讓除錯更困難。最好只捕捉預期的例外。
GO TO FULL VERSION