子类重写父类方法时,throws声明只能缩小不能扩大检查型异常范围,可精简为父类异常的子集、子类或不抛出;运行时异常不受限制。

子类重写父类方法时,throws 声明不能扩大异常范围,但可以精简——即只抛出父类声明的异常的子集,或不抛出任何异常。
必须遵守的规则:只能缩小,不能扩大
Java 要求子类重写方法的 throws 子句不能声明比父类更宽泛的检查型异常(checked exception)。这是为了满足里氏替换原则:用子类对象替换父类对象时,调用方代码不应因异常行为改变而崩溃。
- ✅ 允许:不写
throws(即不抛出任何检查异常) - ✅ 允许:只抛出父类
throws中的某几个异常(子集) - ✅ 允许:抛出父类异常的子类(如父类抛
IOException,子类抛FileNotFoundException) - ❌ 禁止:新增父类未声明的检查异常(如父类没写
throws SQLException,子类不能加) - ❌ 禁止:抛出父类异常的父类(如父类抛
IOException,子类抛Exception)
常见精简写法示例
假设父类方法定义为:
public abstract class DataReader {
public abstract void read() throws IOException, SQLException;
}
子类可这样精简:
-
完全不抛检查异常(最简):
@Override<br>public void read() { /* 可能内部 try-catch 处理掉 */ } -
只抛其中一个:
@Override<br>public void read() throws IOException { /* 不抛 SQLException */ } -
抛具体子类异常(需确保是原异常的子类):
@Override<br>public void read() throws FileNotFoundException { /* FileNotFoundException ⊆ IOException */ }
注意运行时异常(RuntimeException)不受限制
throws 精简规则仅针对检查型异常。子类可以自由添加、删除或修改 RuntimeException 及其子类的声明,编译器不检查——因为它们无需强制处理。
- 父类写
throws IOException,子类写throws IOException, IllegalArgumentException是合法的 - 但这个
IllegalArgumentException声明没有实际约束力,调用方无需try-catch或再throws
实际建议:优先在方法内处理,而非层层上抛
过度依赖 throws 会让异常沿调用链传递,增加上层负担。更健壮的做法是:
- 在子类实现中捕获并处理可预期的检查异常(如文件不存在时提供默认数据)
- 若确实需要暴露异常,选择语义更明确的具体异常类型,而非笼统的父类
- 配合日志记录和上下文补充,让异常信息更有诊断价值
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











