Java异常捕获必须子类在前、父类在后,否则编译报错“unreachable catch block”;同级异常顺序无关,可用多异常语法catch(IOException | SQLException e);业务语义优先时按响应重要性排序。

Java 异常捕获顺序写错,编译器会直接报错,不是运行时才出问题。核心原因是:JVM 按 catch 块从上到下的顺序匹配异常类型,一旦前面的 catch 能接住当前异常(比如用 Exception),后面的更具体的 catch 就永远执行不到,编译器判定为“不可达代码”。
典型报错信息
你看到的错误类似这样:
- error: unreachable catch block for FileNotFoundException. This exception is already caught by the preceding catch block
- error: exception NullPointerException has already been caught
- error: multi-catch can't contain a type that is a subclass of another type in the same catch clause(多异常捕获中混入父子类)
错误写法示例及修正
下面这段代码编译通不过:
try {
readFile();
} catch (Exception e) { // ❌ 错:父类太靠前
log.error("通用异常", e);
} catch (FileNotFoundException e) { // ✅ 本该优先处理,但已被上面吃掉
prompt("文件未找到,请检查路径");
}
正确顺序必须是子类在前、父类在后:
立即学习“Java免费学习笔记(深入)”;
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 先写
catch(FileNotFoundException e) - 再写
catch(IOException e) - 最后才考虑
catch(Exception e)(通常应避免,仅用于兜底日志+重新抛出)
同级异常和多异常捕获
没有继承关系的异常可以任意排列,比如 IOException 和 SQLException 互不继承,顺序无关紧要。
如果它们的处理逻辑完全一样,推荐用 Java 7+ 的多异常语法,更简洁安全:
catch (IOException | SQLException e) {
retryOperation(); // 共享处理逻辑
}
注意:| 不能用于有继承关系的类型,例如 Exception | RuntimeException 是非法的。
业务语义优先的排列逻辑
除了继承关系,还要考虑业务重要性。例如支付场景:
-
catch(PayBalanceInsufficientException e)→ 引导用户充值 -
catch(PayTimeoutException e)→ 启动异步查单,前端显示“处理中” -
catch(IOException e)→ 降级为“请重试”,不暴露细节 -
catch(RuntimeException e)→ 记录完整堆栈并告警
即使某些自定义异常和 IOException 没有继承关系,也按业务响应优先级排布,确保关键逻辑不被覆盖。

















