throw用于手动抛出异常实例,必须是throwable或其子类对象;throws用于声明方法可能抛出的受检异常,写在方法签名后,两者协同实现分层异常处理。

throw 用于手动抛出异常对象
throw 是一个执行语句,出现在方法体内部,作用是立即中断当前流程,并把一个具体的异常实例“扔出去”。它后面必须跟一个 Throwable 或其子类的实例,比如 new IllegalArgumentException("用户名不能为空")。不能写成 throw Exception(类名),也不能用非 Throwable 类型(如 String)。
常见使用场景包括:
- 参数校验失败时,如传入 null 或负数 ID
- 业务规则被破坏,例如余额不足却发起扣款
- 状态不合法,比如订单已关闭还尝试发货
一旦执行 throw,后续代码不再运行,异常会沿着调用栈向上寻找匹配的 catch 块。没被捕获就终止当前线程。
throws 用于声明方法可能抛出的异常类型
throws 写在方法签名末尾、参数列表之后、方法体之前,作用是提前告知调用者:这个方法可能会甩出哪些异常。它不抛出异常,只是做承诺或警告。可以声明多个异常,用逗号分隔,例如:public void readFile() throws IOException, SQLException。
关键规则:
- 只对 受检异常(Checked Exception) 强制要求声明,比如 IOException、SQLException
- 运行时异常(RuntimeException 及其子类)可声明也可不声明,编译器不强制
- 子类重写父类方法时,throws 声明的异常范围不能比父类更宽
两者配合使用的典型流程
实际开发中,throw 和 throws 往往协同工作:底层方法用 throw 抛出具体异常,上层方法用 throws 声明它,再由最外层(如 controller 或 main)用 try-catch 处理。
例如:
- service 方法内检测到非法金额,
throw new BusinessException("金额不能为负") - 该 service 方法签名写
public void transfer(...) throws BusinessException - 调用方捕获
BusinessException并返回友好提示给用户
这种分层处理让错误信息清晰、责任明确,也避免了在每层都写重复的 try-catch。
避免常见误区
不少开发者容易混淆或滥用这两个关键字:
- 误用
throw Exception—— 必须是实例,不是类名 - 在不需要的地方滥用 throw 做流程控制 —— 比如用
throw new RuntimeException("success")表示正常结束,这会拖慢性能(堆栈生成开销大) - 忘记为受检异常加 throws 或 try-catch,导致编译失败
- 自定义异常未继承 Exception 或 RuntimeException,导致 throw 编译报错
记住:throw 是“动作”,throws 是“说明书”。动作要准,说明书要实。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











