throws关键字用于声明方法可能抛出的检查型异常,不处理异常而交由调用者处理;必须声明Checked Exception,不可声明更宽泛的异常类型,与try-catch分工协作。

throws 关键字不是用来处理异常的,而是把异常声明推给调用者——它不捕获、不解决,只甩锅。
什么时候必须写 throws
当你在方法里调用了可能抛出 Checked Exception(比如 IOException、SQLException)的代码,又不想在当前方法用 try-catch 处理,就必须在方法签名后加 throws 声明。
-
RuntimeException及其子类(如NullPointerException、ArrayIndexOutOfBoundsException)不用声明,编译器不管 - 一个方法可以声明多个异常,用逗号分隔:
throws IOException, SQLException - 子类重写父类方法时,
throws的异常类型不能比父类更宽(只能相同或更具体)
throws 和 try-catch 不是二选一,而是分工关系
throws 是“我不处理,你来管”;try-catch 是“我接手,我兜底”。两者可共存:内部先局部处理一部分异常,剩下不确定或不归自己管的,再往上抛。
- 常见误用:在已经
catch了所有可能异常的方法里还写throws——编译报错,因为没异常可抛了 - 正确做法:只对真正可能逃逸出去的
Checked Exception声明throws - 如果
catch里又手动throw new RuntimeException(...),不需要声明throws,但调用方得知道这可能是运行时崩
容易被忽略的继承细节
子类方法覆盖父类方法时,throws 列表受严格限制。这是为了保证多态调用安全——上层代码按父类声明做准备,子类不能突然抛出它没防备的异常。
立即学习“Java免费学习笔记(深入)”;
- 父类方法声明
throws IOException,子类可以throws FileNotFoundException(它是IOException子类),也可以不写throws - 但子类不能
throws SQLException,哪怕逻辑上真发生了——编译直接拒绝 - 若父类没写
throws,子类也不能加(除非抛的是RuntimeException)
public class FileReader {
// 正确:声明可能抛出的检查型异常
public String read(String path) throws IOException {
return Files.readString(Paths.get(path));
}
// 错误示例(编译不过):父类没 throws,子类却加了
// @Override
// public String read(String path) throws IOException { ... }
}
最常踩的坑,是以为写了 throws 就算“处理了异常”,其实只是延迟了责任归属。调用链顶端(比如 main 方法或 Servlet 的 doGet)往往不得不面对这个甩过来的异常——那时才真正需要决定:记录日志?转成用户友好的提示?还是让服务挂掉?










