子类异常必须写在父类异常前面,否则编译直接失败;因为java按catch从上到下匹配,父类如exception会提前捕获所有子类异常,导致后续catch块不可达,编译器静态检查报“unreachable catch block”。

子类异常必须写在父类异常前面,否则编译直接失败——这不是运行时逻辑问题,而是Java编译器强制执行的静态检查规则。
为什么顺序不能颠倒
Java按catch块从上到下的顺序逐个匹配异常类型。只要抛出的异常对象是某个catch参数类型的实例或其子类,就立即进入该块执行,后续catch不再检查。
- 如果Exception写在IOException前面,所有IOException都会被Exception捕获,后面的IOException块永远无法执行
- 编译器会报错:“Unreachable catch block”或“exception XXX has already been caught”
- 这个检查发生在编译期,哪怕你确定某次只抛NullPointerException,只要Exception在它前面,代码就通不过编译
怎么判断谁是子类、谁是父类
关键看继承关系:子类更具体,父类更宽泛。比如:
- FileNotFoundException ← IOException ← Exception
- SQLException和IOException都继承自Exception,但彼此无关(并列)
- NullPointerException ← RuntimeException ← Exception
不确定时,用IDE快捷键(如IntelliJ按Ctrl+Click)跳转到异常类定义,看它extends谁,就能理清层级。
正确排列的实际写法
按“由具体到宽泛”的粒度组织,兼顾可读性与健壮性:
- 业务自定义异常(如UserAlreadyExistsException)
- 标准受检异常(如SQLException、IOException)
- 运行时异常(如IllegalArgumentException、NullPointerException)
- 兜底的Exception(仅用于日志记录或统一包装,慎用)
同级异常(如SQLException和IOException)谁先谁后都合法,但建议按业务发生频率或处理优先级排。
多异常捕获(|语法)的注意事项
Java 7+支持一个catch处理多种异常,例如catch (IOException | SQLException e),但有严格限制:
- 竖线分隔的每个类型之间不能存在继承关系(否则编译报错:“alternative exception types must be disjoint”)
- 变量e的静态类型是这些异常的最近公共父类(通常是Exception),不能直接调用子类特有方法
- 不能写catch (IOException | FileNotFoundException e)——后者是前者的子类,违反规则
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











