子类重写父类方法时,检查异常只能缩小或持平,不可扩大;运行时异常不受限;父类未声明检查异常则子类不得新增;多态调用下异常捕获以编译时类型声明为准。

子类重写父类方法时,异常处理不是自由发挥,而是受编译器强制约束的契约行为——核心就一条:子类不能扩大检查异常(checked exception)的范围。运行时异常(RuntimeException 及其子类)完全不受限,可随意抛、可新增、可不抛。
检查异常必须遵守“缩小或持平”原则
父类方法声明 throws IOException,子类重写时:
- 可以写
throws IOException(完全一致) - 可以写
throws FileNotFoundException(它是 IOException 的子类,范围更窄) - 可以不写
throws(相当于范围缩为“无”) - 但绝不能写
throws Exception或throws SQLException(二者与 IOException 无继承关系,或层级更宽)
父类没声明检查异常,子类就不能加
如果父类方法签名是 void save()(无 throws),子类覆盖时:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 不能写
throws IOException,也不能写throws SQLException - 若内部调用了可能抛检查异常的方法,必须用
try-catch消化掉,再决定是转成运行时异常、返回默认值、记录日志,或静默忽略(慎用) - 可以自由抛
IllegalArgumentException、NullPointerException等运行时异常,编译器不管
常用合规应对方式
当业务确实需要表达新错误语义,又不能改父类签名时:
立即学习“Java免费学习笔记(深入)”;
- 用
RuntimeException包装:如throw new RuntimeException("DB timeout", e),注意必须传入原始异常作 cause - 定义业务级运行时异常:如
ValidationFailedException,在 Javadoc 中明确说明触发条件 - 前置校验替代异常:如
Objects.requireNonNull(param, "param required") - 改用返回值建模:例如
Result<User, Error>,把错误作为数据类型显式传递
多态调用下异常捕获只看编译时类型
这是容易踩坑的关键点:
-
InputStream is = new FileInputStream("x.txt"); is.read();—— 编译器只认InputStream.read()声明的IOException - 即使实际执行的是
FileInputStream.read()并抛出FileNotFoundException,你也不能直接catch FileNotFoundException - 必须按父类契约来捕获:要么
catch IOException,要么在调用处throws IOException

















