必须子类异常在前、父类在后,因为异常匹配从上到下逐个检查,父类若在前会提前捕获所有子类实例,导致后续子类catch块不可达而编译失败。

在多 catch 块中,必须按“子类异常在前、父类异常在后”的顺序排列,否则编译会报错——因为父类异常会提前捕获所有子类实例,导致后续更具体的 catch 块永远无法执行。
为什么必须子类在前?
Java(以及 C# 等语言)的异常匹配是**从上到下逐个检查**的。一旦某个 catch 的参数类型能匹配抛出的异常对象(包括其子类),就立即进入该块,不再继续往下看。如果把 Exception 放在 IOException 前面,那么所有 IOException 实例都会被 Exception 捕获,后面的 IOException 块就变成不可达代码(unreachable),编译器直接拒绝。
正确写法示例(Java)
以下是一个符合要求的多 catch 结构:
try {
// 可能抛出多种异常的代码
readFile("config.txt");
} catch (FileNotFoundException e) { // 子类:最具体
System.err.println("文件未找到:" + e.getMessage());
} catch (IOException e) { // 父类:较宽泛
System.err.println("IO 错误:" + e.getMessage());
} catch (Exception e) { // 更宽泛的父类(如需兜底)
System.err.println("其他异常:" + e.getMessage());
}常见错误与规避方法
- 编译报错 “exception XXX has already been caught”:说明你把父类写在了子类前面,调换顺序即可。
-
IDE 提示 “Unreachable catch block”:这是明确提醒你某段
catch永远不会执行,应删掉或重排。 -
多个同级子类可任意顺序:比如
SQLException和IOException无继承关系,谁先谁后都可以,但都必须排在它们共同父类(如Exception)之前。 -
使用多异常捕获(Java 7+)要谨慎:如
catch (IOException | SQLException e),其中列出的异常类型不能存在继承关系,否则编译失败。
小技巧:快速理清继承关系
不确定异常间是否父子关系时,可以查 JDK 文档或 IDE 快捷键(如 IntelliJ 按 Ctrl+Click 进入异常类定义),重点看 extends 或 implements 部分。常见层级举例:
-
FileNotFoundException→IOException→Exception -
NullPointerException→RuntimeException→Exception -
ArithmeticException→RuntimeException→Exception

















