必须子类异常在前,因为Java按catch块从上到下匹配异常类型,父类在前会导致子类catch成为死代码而编译报错。

多个 catch 块必须按子类异常在前、父类异常在后的顺序排列,否则编译不通过。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
为什么必须子类在前?
Java 按照 catch 块从上到下的顺序匹配异常类型。一旦某个 catch 参数能接收当前抛出的异常(即该异常是参数类型的实例或子类),就执行对应块,后续 catch 不再检查。如果父类写在前面,比如 Exception 放第一个,那么所有子类异常(如 NullPointerException、IOException)都会被它“提前捕获”,后面的子类 catch 就永远无法执行,变成死代码——编译器会直接报错:“exception XXX has already been caught”。
正确排列的规则
- 同一个
try后的多个catch,必须按继承关系由具体到宽泛排序 - 常见组合示例(合法):
catch (FileNotFoundException e)catch (IOException e)catch (Exception e)
- 运行时异常(
RuntimeException及其子类)和编译时异常可混排,但仍需遵守子类优先原则。例如:catch (IllegalArgumentException)应在catch (RuntimeException)之前 - 同级异常(无继承关系)顺序任意,比如
IOException和SQLException可以互换位置
容易踩的坑
- 把
Exception或Throwable放在最前面——这是最常见的编译错误来源 - 误以为“先写更常见的异常”更高效——实际匹配只看类型兼容性,不看发生频率
- 用多层嵌套
try-catch替代合理排序——增加复杂度且未必解决问题 - 忽略自定义异常的继承链——如果自定义异常继承了
IOException,那它必须排在IOException之前
一个典型正确写法
// 示例:读取并解析文件
try {<br>
FileInputStream fis = new FileInputStream("data.txt");<br>
ObjectInputStream ois = new ObjectInputStream(fis);<br>
MyData data = (MyData) ois.readObject();<br>
} catch (FileNotFoundException e) {<br>
// 文件不存在<br>
} catch (ClassNotFoundException e) {<br>
// 反序列化时类找不到<br>
} catch (IOException e) {<br>
// 其他 IO 异常,如流关闭失败、读取中断等<br>
} catch (ClassCastException e) {<br>
// 类型转换失败,运行时异常<br>
} catch (Exception e) {<br>
// 兜底:其他未预期的异常(慎用,建议记录日志后重新抛出)<br>
}

















