java异常捕获必须子类在前、父类在后,否则编译报错unreachable catch block;同级异常可任意排序,多异常捕获(|)要求类型无继承关系,兜底异常须置于最后且禁用throwable。

Java 异常捕获顺序必须按“子类在前、父类在后”排列,否则编译器会直接报错 Unreachable catch block 或 exception XXX has already been caught。这不是警告,而是硬性编译失败,代码根本无法生成 class 文件。
核心规则:继承关系决定先后顺序
只要两个异常类型存在 is-a 关系(即一个继承自另一个),就必须把更具体的子类写在前面,宽泛的父类写在后面。JVM 按 catch 块从上到下的顺序匹配,一旦命中就停止检查,后面的块永远不会执行。
-
正确示例:
catch (FileNotFoundException e)→catch (IOException e)→catch (Exception e) -
错误示例(编译不通过):
catch (Exception e)→catch (IOException e)(被前面的 Exception 完全覆盖) - 同级异常(无继承关系)可自由排序,比如
IOException和SQLException谁先谁后都合法,但建议按业务常见度或模块分组排列
多异常捕获(|语法)也有顺序限制
Java 7+ 支持一个 catch 块捕获多种异常,但前提是这些类型之间不能有父子继承关系。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
合法:
catch (IOException | SQLException e)(二者最近公共父类是 Exception) -
非法:
catch (IOException | FileNotFoundException e)(后者是前者的子类,编译报错) - 此时变量
e的静态类型是它们的最小公共父类,不能直接调用子类特有方法,需先instanceof判断再转型
兜底异常要放在最后,且慎用
用 Exception 或更宽泛类型做收口是常见做法,但它必须排在所有具体异常之后。
- 如果把它放在最前面,后续所有
catch都失效,编译直接拒绝 - 避免使用
Throwable或Error作为捕获目标——前者涵盖Error,后者属于 JVM 严重故障,不应由业务代码处理 - 真正需要区分处理的异常(如
SQLTimeoutExceptionvsSQLException)必须单独列出,且子类优先
IDE 和编译器是你的第一道防线
现代 IDE(如 IntelliJ IDEA、Eclipse)会在编辑时高亮非法顺序,并提供一键修复建议。即使忽略提示,javac 编译阶段也必然报错,不会生成字节码。把异常顺序当作“编译期契约”来对待,比运行时调试更高效可靠。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










