throw是立即抛出异常实例,程序停在该行;throws是方法声明可能抛出的受检异常类型,仅编译期检查。throw后必须是异常对象,throws后只能是异常类名,可多个逗号分隔。
throw 是“真扔”,throws 是“预告要扔”
你写 throw 的那一刻,程序立刻停在那一行,异常对象被创建并上抛;而 throws 只是方法签名上的一行声明,编译器靠它检查调用链是否合规,运行时完全不生效。
-
throw后面必须是new XXXException("msg")这样的异常实例,不能是类名——写成throw IllegalArgumentException;直接编译报错 -
throws后面只能是异常类型(如IOException、SQLException),可多个,用逗号分隔;但声明了不代表一定会抛,只是“可能” - 一个方法里可以有多个
throw(比如不同 if 分支抛不同异常),但throws在方法头只出现一次
什么时候必须用 throws?——受检异常的硬性门槛
当你 throw 一个受检异常(checked exception),比如 FileNotFoundException 或 IOException,编译器会强制你处理:要么用 try-catch 包住,要么在方法声明加 throws 推给上层。漏掉就过不了编译。
- 运行时异常(
RuntimeException及其子类)不受此限:throw new NullPointerException()可以直接写,不用throws,也不用try-catch - 子类重写父类方法时,
throws声明的异常类型不能比父类更宽——比如父类声明throws IOException,子类只能throws FileNotFoundException(它是IOException子类)或不声明 - 常见误操作:在工具类方法里
throw new SQLException()却没加throws,结果编译失败,不是代码逻辑错,是契约没签好
throw 和 throws 经常一起出现,但职责绝不混用
典型协作场景是「底层资源操作 + 上层业务校验」:方法内部用 throw 主动拦截非法输入,同时用 throws 声明可能触发的 I/O 异常。