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 块。 忽略错误会导致“静默”缺陷。至少要输出消息或记录异常。
错误 5:一把抓所有 Exception。 使用 catch (Exception e) 会掩盖真实问题,增加调试难度。最好只捕获预期的异常。
GO TO FULL VERSION