throws用于方法签名中声明可能抛出的检查型异常,强制调用方处理;只能声明checked exception,不可新增父类未声明的检查型异常;典型用于io、数据库等底层操作及分层架构中的责任传递。

throws写在方法签名上,只声明不处理
它不是用来捕获异常的,而是告诉调用者:“我可能抛出这个异常,你得自己想办法”。编译器会强制检查——如果方法声明了throws IOException,而你没用try-catch包住,或者没在调用处继续throws,编译直接失败。
-
throws后面跟的是异常类型(类名),可以多个,用逗号分隔:throws IOException, SQLException - 只能声明**检查型异常(checked exception)**,比如
IOException、ClassNotFoundException;运行时异常(RuntimeException及其子类)加不加throws都合法,但毫无意义 - 子类重写父类方法时,
throws声明不能比父类更宽——不能新增父类没声明的检查型异常
什么时候必须用throws而不是try-catch
当你明确不想(或不适合)在当前方法里处理异常,且调用方更有能力决定怎么应对时。典型场景是底层IO操作、数据库连接、文件读写等。
- 工具类中的通用方法:比如一个
readConfigFile(String path),它不该决定“文件不存在就弹窗还是退出程序”,只负责抛出FileNotFoundException - Spring Controller里常把自定义业务异常统一抛给全局异常处理器,所以Service方法直接
throws BizException - main方法里也可以
throws,JVM会打印堆栈并退出——这反而是最干净的收尾方式,比如public static void main(String[] args) throws IOException
常见错误:混淆throws和throw,或乱加RuntimeException
很多人看到编译报错就随手补throws Exception,结果埋下隐患。
-
throw是语句,用于手动抛出异常对象;throws是方法签名的一部分,声明可能抛出的类型——别把throw new RuntimeException()错写成throws new RuntimeException() - 不要为了过编译而写
throws Exception:它掩盖真实异常类型,调用方无法针对性处理,也破坏API契约 - 给
NullPointerException或IllegalArgumentException加throws纯属多余,编译器不管,IDE还会标灰提示 - 如果方法内部调用了声明
throws的方法,你有两个选择:自己try-catch,或者在自己方法签名上也throws——不能假装看不见
异常向上传递时的链路与责任边界
异常不会自动“消失”,它沿着调用栈向上找第一个能处理它的地方。throws就是你在这一环中主动划出的责任线。
立即学习“Java免费学习笔记(深入)”;
- 从DAO层抛
SQLException→ Service层转为BizException再throws→ Controller层捕获并返回HTTP 500——这是常见分层处理模式 - 如果中间某层既不
catch也不throws,编译失败;如果写了catch却什么也不做(空块),等于吞掉异常,后续排查基本靠猜 - 注意异常包装:用
new BizException("配置加载失败", e)保留原始cause,否则调用方看到的只是新异常,丢掉了关键堆栈
throws本身。








