throw用于方法体内抛出具体异常对象,throws用于方法声明处声明可能抛出的受检异常;前者执行即中断流程,后者仅为契约声明,二者需配合使用以明确异常责任。

throw 和 throws 是 Java 异常处理中两个基础但易混淆的关键字,一个管“怎么扔”,一个管“说要扔什么”。用错位置或混用逻辑,轻则编译报错,重则掩盖真实错误、破坏调用链责任划分。
throw 是实际抛出异常的动作
它出现在方法体内部,后面必须跟一个具体的异常对象实例,执行到这一行就立刻中断当前流程,把异常交给上层处理。
- 语法格式:`throw new IllegalArgumentException("参数不合法");`
- 只能抛一个异常,一次一条 throw 语句
- 可以抛受检异常(如 IOException)或非受检异常(如 NullPointerException、RuntimeException 子类)
- 如果 throw 的是受检异常,所在方法必须用 throws 声明,或用 try-catch 捕获——否则编译不通过
throws 是对调用方的异常承诺
它写在方法声明末尾,紧接在参数列表之后、方法体之前,作用是告诉所有调用者:“我这个方法可能会甩出这些异常,请你做好准备。”
- 语法格式:`public void readFile() throws IOException, SQLException`
- 不创建也不抛异常,只是声明可能性;多个异常用英文逗号分隔
- 主要面向受检异常——非受检异常声明了也不强制调用方处理
- 若方法内部 throw 了受检异常但没在方法签名加 throws,编译直接报错
典型配合场景:封装工具方法时的责任分离
比如写一个读配置文件的工具方法,底层调用 FileInputStream 会触发 IOException。你不想在工具方法里处理它(因为不知道调用方想怎么恢复),那就用 throws 向外声明:
public static String readConfig(String path) throws IOException {
FileInputStream in = new FileInputStream(path);
return IOUtils.toString(in, "UTF-8");
}
而调用方要么 try-catch 处理,要么继续 throws 上去。如果某处业务逻辑发现路径为空,你可以主动 throw 自定义异常:
if (path == null || path.trim().isEmpty()) {
throw new IllegalArgumentException("配置路径不能为空");
}
常见误区与设计提醒
- 不要在同一个方法里又 throws 又在内部 try-catch 再 throw 新异常——容易造成异常信息丢失或嵌套过深
- throws 列太多异常(比如超过 3–4 个),往往说明方法职责太杂,建议拆分或统一包装成业务异常
- throw new Exception() 这种泛化写法应避免;优先用语义明确的子类,如 IllegalArgumentException、IllegalStateException
- Java 7+ 支持 catch 多异常(`catch (IOException | SQLException e)`),但 throws 不支持类似简写,仍需逐个列出

















