Java方法重写时检查异常只能缩小或保持不变,禁止扩大;父类未声明检查异常则子类不得添加;运行时异常不受限制;设计上宜用通用异常类型、组合模式或Result封装优化。

Java 继承中方法重写的异常抛出,核心是守住“检查异常契约不扩大”这条红线——子类不能让调用方突然面对父类没承诺过的检查型异常。
检查异常必须缩小或保持一致
父类方法声明 throws IOException,子类重写时只允许:
- 不写
throws(即完全不抛检查异常) - 仍写
throws IOException(类型完全一致) - 改写为更具体的子类,如
throws FileNotFoundException或throws SocketTimeoutException
禁止写 throws Exception、throws SQLException(与 IOException 无继承关系)、或同时声明多个无关检查异常。编译器会直接报错:“overridden method does not throw …”
父类没声明检查异常,子类也不能加
如果父类方法签名是 void doWork()(无 throws),子类重写时:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 不得添加任何
throws声明,哪怕只是IOException - 若内部调用了可能抛检查异常的代码(如
FileInputStream构造、JDBC 操作),必须用try-catch拦住 - 常见做法是捕获后包装为运行时异常:
throw new RuntimeException("read config failed", e)
运行时异常可自由使用
RuntimeException 及其子类(如 IllegalArgumentException、IllegalStateException)不受重写规则限制:
- 子类可以新增、删减、替换这些异常的
throws声明(甚至不写也合法) - 它们不参与编译检查,不影响调用方的异常处理逻辑
- 适合封装底层检查异常,保留上下文又不破坏契约,例如:
catch (SQLException e) { throw new DataAccessException("insert failed", e); }
设计层面更稳妥的选择
与其在重写时绕规则兜底,不如从源头优化:
- 父类方法的
throws声明应反映共性——如果多个子类确实需要抛不同检查异常,说明抽象层级可能不够,考虑提升到更通用类型(如throws StorageException自定义基类) - 当异常语义差异大时,优先用组合或策略模式替代深度继承,把异常处理逻辑解耦出来
- 对调用方友好的方式,是统一返回
Result或Optional,把异常消化在方法内部,避免暴露复杂异常体系
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










