CodeGym /课程 /JAVA 25 SELF /复杂的异常处理与最佳实践

复杂的异常处理与最佳实践

JAVA 25 SELF
第 24 级 , 课程 3
可用

1. 多个 catch:处理不同的异常

在真实程序中,同一段代码可能抛出不同类型的异常。比如读取文件时可能出现 FileNotFoundExceptionIOException,而解析数据时还可能出现 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 时,应尽量抛出具体的异常,而不是仅仅抛出 ExceptionRuntimeException。这会让你的代码和接口对其他开发者更清晰。

示例:

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) 会掩盖真实问题,增加调试难度。最好只捕获预期的异常。

评论 (1)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
ncksllpo 级别 44,Cherkasy,Ukraine
12 二月 2026
两题