受检异常必须显式处理:要么用try-catch在方法内消化,要么用throws声明推给调用者;后者更常见,适用于底层操作层,强调职责分离与契约保障。

方法签名中出现受检异常,必须明确告诉调用者“这里可能出问题”,不能忽略或绕过编译检查。核心就两条路:要么在方法内部用 try-catch 消化掉,要么在方法声明里用 throws 推给上层。
用 throws 声明抛出受检异常
这是最常见、也最符合语义的做法——当方法本身不适合处理(比如读文件失败,业务层不知道该重试还是提示用户),就让调用者决定怎么应对。
- 语法是在方法签名末尾加 throws 异常类名,多个用逗号分隔,例如:
public void saveToFile() throws IOException, SQLException - 声明后,编译器会强制要求调用方处理:要么继续 throws,要么用 try-catch 捕获
- 注意:只声明受检异常有效;RuntimeException 及其子类加 throws 不起作用,编译器不拦,但可以写,仅作文档用途
在方法内部用 try-catch 处理掉
如果当前方法能合理恢复或兜底(比如文件不存在就创建默认配置),就可以自己消化,不向外暴露异常。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 把可能抛出受检异常的代码放进 try 块,catch 对应异常类型,做日志、默认值、重试等操作
- catch 后不要空着,至少记录日志;也不要简单吞掉异常还假装成功
- 如果 catch 里无法完全处理,可以转换成更上层能理解的业务异常,再 throw 出去(比如把 IOException 封装成 ConfigLoadException)
避免常见错误写法
有些做法看似绕过了编译报错,实则埋下隐患:
- 用
catch (Exception e) { }空捕获 —— 异常消失了,但问题还在,调试困难 - 把受检异常转成 RuntimeException 包装后抛出(如
throw new RuntimeException(e))—— 虽然编译通过,但丢失了“必须处理”的契约,调用方容易遗漏 - 在 lambda 或函数式接口里遇到受检异常,硬套 try-catch 导致代码臃肿 —— 可考虑封装工具方法或使用支持受检异常的第三方接口(如 jOOQ 的
Unchecked.function)
实际选哪条路,看职责边界
关键不是技术能不能做,而是“谁更适合响应这个异常”:
- IO、网络、数据库操作层通常只声明 throws,因为它们只管执行,不管业务逻辑怎么应对
- Service 层根据场景二选一:可恢复的就 try-catch + 补偿;需人工介入的就 throws 给 Controller 层统一返回错误码或页面提示
- Controller 层一般要 catches 所有未声明的受检异常,转成用户友好的响应,避免堆栈暴露到前端
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










