必须子类异常写在前面,因为jvm按catch顺序从上到下匹配,父类若在前会拦截所有子类异常,导致后续子类catch不可达而编译失败。

Java中多个catch块的排列顺序必须遵循“子类在前、父类在后”的原则,否则编译不通过;这是由异常类型的继承关系和JVM的匹配机制决定的。
为什么必须子类异常写在前面
catch块按代码书写顺序从上到下依次匹配,一旦某个异常类型能捕获当前抛出的异常对象(即该异常是catch声明类型的实例或其子类),就立即执行对应块,后续catch不再检查。如果父类异常写在前面,它会提前“拦截”所有子类异常,导致后面的子类catch永远无法到达,形成不可达代码。
例如:
try {
throw new IOException();
} catch (Exception e) { // 父类太宽,会捕获所有Exception子类
System.out.println("Exception");
} catch (IOException e) { // 编译报错:Unreachable catch block
System.out.println("IO");
}
合法的排列规则
- 同一try后,多个catch中声明的异常类型不能存在继承关系,除非子类在前、父类在后
- 并列无关的异常类(如IOException和SQLException)可以任意顺序,但建议按常见程度或业务逻辑分组
- RuntimeException及其子类也受此约束,比如NullPointerException必须写在Exception之前
- 即使使用多异常捕获语法(|),各类型之间也不能有父子关系,否则编译报错
实际编写建议
- 按具体到宽泛的粒度组织:先捕获明确的业务异常(如UserNotFoundException)、再系统异常(如SQLException)、最后兜底(Exception)
- 避免直接捕获Throwable或Error,它们不属于正常业务处理范畴
- 若需统一日志或资源清理,优先用finally或try-with-resources,而非依赖靠后的通用catch
- IDE通常会提示“Catch clause order”警告,可作为检查依据
小技巧:快速判断是否合法
把每个catch参数类型画成继承树,从叶子节点(最具体)开始向上写——只要路径上没有“跳过父节点直接写孙子”,且代码中子类声明严格出现在所有其父类之前,就是安全的。
本质上这不是Java的“限制”,而是对开发者意图的保护:防止你写了却永远不被执行的异常处理器。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











