子类异常必须写在父类异常之前,否则编译报错;java按catch从上到下匹配异常类型,先匹配成功即执行,后续忽略;正确顺序应由具体到宽泛,如filenotfoundexception→ioexception→exception。

多重 catch 块中,子类异常必须写在父类异常之前,否则编译器会报错:“已捕获到异常的子类型”。这是 Java 的强制语义规则,目的是保证异常处理逻辑的精确性和可预测性。
理解“先匹配、先执行”的捕获机制
Java 按 catch 块从上到下的顺序逐个比对异常类型。一旦某个 catch 参数能向上转型(is-a 关系)匹配当前抛出的异常实例,就立即进入该块执行,后续 catch 不再检查。若父类写在前面,子类 catch 就永远无法到达——编译器提前拦截这种无意义代码。
正确排列:子类优先,父类靠后
按继承层级由具体到宽泛排列:
-
最具体的异常类型放最前:如
IOException→SQLException→Exception -
同级异常顺序无关紧要:如
FileNotFoundException和EOFException都是IOException子类,可互换位置 -
避免用
Exception或Throwable打头:否则后面所有catch都失效,编译直接报错
常见错误与修正示例
❌ 错误写法(编译不通过):
try { /* ... */ }
catch (Exception e) { /* 父类太宽泛,挡住了所有子类 */ }
catch (IOException e) { /* 永远不会执行 → 编译错误 */ }✅ 正确写法(按具体性降序):
try { /* ... */ }
catch (FileNotFoundException e) { /* 最具体 */ }
catch (IOException e) { /* 更宽泛,但仍是受检异常 */ }
catch (IllegalArgumentException e) { /* 另一条继承线上的具体异常 */ }
catch (RuntimeException e) { /* 非受检异常父类 */ }
catch (Exception e) { /* 所有其他受检异常兜底 */ }借助 IDE 和编译器及时发现隐患
现代 IDE(如 IntelliJ IDEA、Eclipse)会在编辑时高亮非法顺序,并给出快速修复建议。即使暂时忽略警告,javac 编译阶段也必然报错,不会生成 class 文件。因此,把异常顺序当作“编译期契约”来对待,比运行时调试更高效可靠。











