throws必须写在方法签名末尾、参数列表右括号后、方法体左大括号前,仅用于声明检查型异常;多个异常用逗号分隔,子类不可与父类重复声明;调用方必须捕获或继续throws,否则编译失败。

throws 必须写在方法签名末尾,紧跟参数列表之后
Java 中 throws 不是语句,而是方法声明的一部分,语法位置非常固定:在参数列表右括号后、方法体左大括号前。写错位置(比如塞进方法体内或放在返回类型前)会直接编译失败。
常见错误现象:Syntax error on token "throws", delete this token 或 invalid method declaration; return type required,往往是因为把 throws 当成执行逻辑写了,或者和 throw 混淆了。
-
void readFile() throws IOException✅ 正确位置 -
void readFile() { throws IOException ... }❌ 不能在方法体内 -
throws IOException void readFile()❌ 不能放在返回类型前
只能声明检查型异常(Checked Exception),运行时异常(RuntimeException)可选声明
Java 强制要求:如果方法体内调用了可能抛出检查型异常(如 IOException、SQLException)的代码,又没用 try-catch 处理,就必须在方法签名中用 throws 声明——否则编译不通过。
而 NullPointerException、IllegalArgumentException 这类运行时异常,即使不声明也能编译通过;声明它们不是强制的,但有时为了 API 清晰或文档提示,也会显式写出。
- 必须声明:
FileInputStream(String name) throws FileNotFoundException - 可声明可不声明:
public void validate(String s) throws IllegalArgumentException - 声明了运行时异常 ≠ 能避免抛出,只是告诉调用方“这里可能出这个错”
多个异常用逗号分隔,子类异常不必重复声明父类
一个方法可能因不同路径抛出多种检查型异常,全部列在 throws 后,用英文逗号分隔。注意:如果已声明了父类异常(如 Exception),再写它的子类(如 IOException)是冗余且编译报错的——Java 不允许子类异常出现在父类之后。
使用场景:比如文件操作既要处理编码问题(UnsupportedEncodingException),又要处理读取失败(IOException),就得都列出来。
- ✅ 正确:
void process() throws IOException, SQLException - ✅ 正确(只写父类):
void process() throws Exception - ❌ 错误:
void process() throws Exception, IOException(子类在父类后)
调用方必须处理或继续上抛,否则编译失败
这是 throws 最关键的约束:一旦方法 A 声明了检查型异常,所有直接调用 A 的方法 B,要么用 try-catch 捕获它,要么在自己的签名里也用 throws 继续声明——没有第三种选择。
容易踩的坑是以为“我写了 throws 就算处理完了”,其实只是把责任移交给了上层;如果一路推到 main 方法还没捕获,最终程序崩溃时异常栈依然会打印出来。
- 调用方处理:
try { readFile(); } catch (IOException e) { ... } - 调用方上抛:
public static void main(String[] args) throws IOException - 如果
main也不处理也不上抛,编译直接报错:Unhandled exception type IOException
真正难的不是写 throws,而是判断该由谁来处理异常:是当前方法兜底,还是让调用方决定重试、降级或告警?这个决策比语法本身影响更大。

















