子类异常必须写在父类异常前面,否则编译失败;Java按catch从上到下匹配,子类异常(如FileNotFoundException)须置于父类(如IOException)之前,Exception等顶层异常应放最后;多异常捕获(|)要求类型互不继承。

子类异常必须写在父类异常前面,否则编译直接失败——这不是运行时逻辑问题,而是 Java 编译器强制执行的静态检查规则。
必须按“从具体到宽泛”排列
Java 按 catch 块从上到下的顺序逐个匹配异常类型。只要抛出的异常对象是某个 catch 参数类型的实例或其子类,就立即进入该块执行,后续 catch 不再检查。因此:
- 最具体的子类异常(如 FileNotFoundException)必须放在最上面
- 它的直接父类(如 IOException)紧随其后
- 顶层通用异常(如 Exception)只能放在最后,且应慎用
判断继承关系的关键方法
不确定谁是子类、谁是父类时,关键看继承链:
- FileNotFoundException ← IOException ← Exception
- NullPointerException ← RuntimeException ← Exception
- SQLException 和 IOException 都继承自 Exception,但彼此无关,可任意顺序
- 用 IDE(如 IntelliJ)按 Ctrl+Click 跳转到异常类定义,查看 extends 后的父类,能快速理清层级
多异常捕获(|语法)的使用边界
Java 7+ 支持一个 catch 处理多种异常,例如 catch (IOException | SQLException e),但有严格限制:
立即学习“Java免费学习笔记(深入)”;
- 竖线分隔的每个类型之间不能存在继承关系,否则编译报错:“alternative exception types must be disjoint”
- 不能写 catch (IOException | FileNotFoundException e),因为后者是前者的子类
- 变量 e 的静态类型是这些异常的最近公共父类(通常是 Exception),不能直接调用子类特有方法
- 若需调用子类方法,须先用 instanceof 判断并显式转型
实用编写建议
实际编码中应兼顾可读性、健壮性和业务语义:
- 优先捕获业务自定义异常(如 UserAlreadyExistsException)
- 再处理标准受检异常(如 SQLException、IOException)
- 接着是运行时异常(如 IllegalArgumentException、NullPointerException)
- 兜底的 Exception 仅用于日志记录或统一包装,避免掩盖问题
- 绝对不要把 Exception 或 Throwable 放在第一个 catch 块


















