throw用于方法内抛出具体异常实例并中断当前执行流,throws用于方法签名声明可能抛出的异常类型;前者必须跟Throwable实例,后者只写异常类名且仅对受检异常强制要求。

throw 是抛出动作,必须写在方法内部
它干一件事:中断当前执行流,把一个具体的异常对象扔出去。不是声明“可能有异常”,而是“现在就出错了”。
-
throw后面跟的必须是Throwable或其子类的实例,比如new IllegalArgumentException("name 不能为空"),不能写类名(如throw IllegalArgumentException) - 常见错误:在
if判断后漏掉return或逻辑分支,导致后续代码仍执行——throw不会自动让方法退出整个流程,只是终止当前路径;但若没加return,编译器可能报错“unreachable statement” - 典型场景:参数校验失败、状态非法(如订单已关闭却调用发货)、业务规则被破坏时主动拦截
throws 是异常声明,只出现在方法签名末尾
它不抛异常,也不做任何事,只是告诉调用者:“我这个方法可能会甩给你这些异常,请你接住。”
-
throws后面跟的是异常**类型名**,可以多个,用逗号分隔,例如:void save(File f) throws IOException, SecurityException - 只对**受检异常(checked exception)** 强制要求声明;运行时异常(如
NullPointerException)加throws是合法但无强制意义的,编译器不管 - 容易踩的坑:在重写父类方法时,子类
throws的异常范围不能比父类更宽(即不能新增父类没声明的受检异常),否则编译失败
throw 和 throws 经常一起用,但角色绝不混用
一个方法既可能自己制造异常(throw),又可能把底层调用的异常原样或包装后继续上抛(throws)。
- 示例:读文件并校验内容长度
public String readFile(String path) throws IOException {- String content = Files.readString(Paths.get(path)); // 底层可能抛
IOException - if (content.length() == 0) throw new IllegalArgumentException("文件内容为空"); // 主动抛运行时异常
-
return content; - }
- 这里
throws IOException是为Files.readString负责;throw new IllegalArgumentException是为业务逻辑负责——两者共存毫无冲突
不处理好 throw/throws,编译器就会卡住你
Java 的受检异常机制是硬性约束,不是风格建议。该声明不声明、该捕获不捕获,直接编译失败。
立即学习“Java免费学习笔记(深入)”;
- 当你调用一个带
throws的方法(比如FileInputStream构造函数),就必须用try-catch包住,或在自己方法上也加throws往上传 - 别试图用
throw new RuntimeException(e)来“绕过”throws声明——这虽然能编译通过,但掩盖了真实异常类型,会让调用方失去处理依据 - 真正难的不是语法,而是判断:这个异常该由当前方法消化(比如重试、降级、打日志后返回默认值),还是该交出去?这个决策比写
throw或throws重要得多








