Java方法重写时,检查型异常必须缩小或去除,运行时异常完全自由;父类未声明检查异常则子类不得添加,否则编译失败。

Java 方法重写时的异常抛出规则,本质是保障多态调用的安全性——编译器只认父类方法声明的异常,不看子类实际抛什么。违反规则会直接编译失败,不是运行时问题,而是契约破坏。
检查型异常必须“缩小或去掉”
只有 编译时异常(checked exception) 受此限制,比如 IOException、SQLException、ParseException 等。子类重写时:
- 若父类方法声明
throws IOException,子类可写throws FileNotFoundException(它是 IOException 的子类) - 可改为
throws IOException(保持一致) - 也可完全不写
throws,即内部用 try-catch 处理掉 - 但绝不能写
throws Exception、throws SQLException(除非它继承自父类声明的异常)或throws Throwable
父类没声明检查异常,子类就不能加
如果父类方法签名是 void doWork()(无 throws),子类重写时:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 不允许添加任何
throws XXXException声明,哪怕只是 IOException —— 编译器立刻报错 - 遇到底层可能抛检查异常的操作(如 new FileInputStream、Class.forName),必须自己捕获
- 常见做法:用
throw new RuntimeException(e)包装后抛出,或使用自定义运行时异常如DataAccessException
运行时异常完全自由
RuntimeException 及其子类(如 IllegalArgumentException、NullPointerException、IllegalStateException)不受任何重写约束:
立即学习“Java免费学习笔记(深入)”;
- 父类方法没声明异常,子类可以自由抛出
throw new IllegalArgumentException("id is null") - 父类已声明
throws IOException,子类仍可额外在方法体中抛throw new IllegalStateException() - 不需要出现在
throws子句中,也不强制调用方处理
更稳妥的实践建议
与其绕规则硬加检查异常,不如从设计上提升健壮性:
- 对业务错误,优先定义语义清晰的 运行时异常子类(如
ValidationFailedException),并在 Javadoc 明确说明触发条件 - 关键路径考虑返回
Result<T, E>或Optional,把错误变成可检查的值,避免异常流扩散 - 前置校验用
Objects.requireNonNull()、Preconditions.checkArgument()拦截明显非法输入,减少异常发生场景 - 若父子类异常语义差异大,可考虑用组合替代继承,把易变的异常逻辑抽到策略类中

















