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

throws 必须写在方法签名末尾,位置错就编译失败
Java 中 throws 不是语句,而是方法声明语法的一部分,位置极其严格:必须紧跟在参数列表右括号 ) 后、方法体左大括号 { 前。写到方法体内、返回类型前、或者和 throw 混用,都会直接报错。
常见错误现象包括:Syntax error on token "throws", delete this token、invalid method declaration; return type required。
-
void readFile(String path) throws IOException { ... }✅ 正确 -
void readFile(String path) { throws IOException { ... } }❌ 不能塞进方法体 -
throws IOException void readFile(String path) { ... }❌ 不能放返回类型前
只能声明检查型异常,运行时异常可选但不强制
throws 的核心约束是面向检查型异常(Checked Exception)——比如 IOException、SQLException、ClassNotFoundException。这些异常不处理或不声明,编译器直接拒绝通过。
而 RuntimeException 及其子类(如 NullPointerException、IllegalArgumentException)属于运行时异常,不声明也能编译成功;显式写出来不是为了过编译,而是为了 API 文档提示或契约约定。
- 必须声明:
FileInputStream(String name)→ 抛出FileNotFoundException,不throws就编译失败 - 可选声明:
public void parse(String s) throws IllegalArgumentException,不写也不报错,但调用方能提前感知风险
多个异常用逗号分隔,父类和子类不能同时声明
一个方法可能因不同路径抛出多种检查型异常,全部列在 throws 后,用英文逗号分隔。但要注意继承关系:如果已声明父类异常(如 Exception),再声明它的任意子类(如 IOException)会导致编译错误。
这不是风格问题,是 Java 明确禁止的冗余声明。
- ✅ 正确:
void process() throws IOException, SQLException - ✅ 正确(只写父类):
void process() throws Exception - ❌ 错误:
void process() throws Exception, IOException(子类出现在父类之后)
调用方必须处理,否则编译失败——这是 throws 的硬性契约
一旦方法 A 声明了 throws IOException,所有直接调用 A 的方法 B,就必须做两件事之一:用 try-catch 捕获,或在自己方法签名中也加 throws IOException(继续上抛)。没得选,编译器会拦住你。
这个机制让异常流向变得可追踪,但也容易在多层调用中被忽略——比如某中间层忘了加 throws,编译失败时错误信息往往指向调用点而非源头。
- DAO 层抛
SQLException→ Service 层必须捕获并转为业务异常,或继续throws - 接口方法声明
throws RemoteAccessException→ 所有实现类都得遵守,哪怕实际没走网络
最容易被忽略的是:这个约束只对检查型异常生效;一旦混入 RuntimeException,契约就“断链”了——它不会强制调用方处理,但可能在运行时突然崩掉。










