受检异常是Java中必须在编译期显式处理的异常,继承自Exception但不继承RuntimeException;典型代表有IOException、SQLException、ParseException等,多由外部环境引发且可恢复;设计目的是强制开发者应对可预期的运行时问题,而非增加负担。

受检异常(Checked Exception)是Java中一类必须在编译期显式处理的异常,它继承自 Exception 类,但**不继承自 RuntimeException**。编译器会强制要求:调用可能抛出受检异常的方法时,要么用 try-catch 捕获,要么在方法签名中用 throws 声明——否则代码无法通过编译。
哪些是典型的受检异常?
它们大多代表**外部环境引发的、可预期且可恢复的问题**,不是代码写错了,而是资源不可用、格式不对或通信失败等客观条件导致的。常见类型包括:
-
java.io.IOException 及其子类:如
FileNotFoundException(文件不存在)、EOFException(读到流末尾)、SocketException(网络断连) -
java.sql.SQLException:如
SQLTimeoutException、SQLSyntaxErrorException,出现在JDBC执行SQL时 -
java.text.ParseException:用
SimpleDateFormat.parse()解析非法日期字符串时抛出 -
java.net.URISyntaxException:构造
URI对象时传入格式错误的字符串 -
java.lang.ClassNotFoundException:动态加载类(如
Class.forName("xxx"))时类路径中找不到该类 - javax.naming.NamingException:JNDI查找资源失败,比如查不到配置的数据源名
为什么设计成“必须处理”?
这不是为了增加开发负担,而是提醒开发者:这类问题大概率会在运行时发生,且往往有合理补救方式。例如:
- 文件没找到 → 可提示用户重新输入路径,或自动创建默认配置文件
- 数据库连接失败 → 可重试、切换备用库、降级返回缓存数据
- URL格式错误 → 可记录日志并返回友好提示,而不是让整个请求崩溃
典型使用场景与写法
关键原则是:**不掩盖、不忽略、不裸 throw**。推荐做法:
立即学习“Java免费学习笔记(深入)”;
- 在工具类或底层方法中保留 throws,把责任交给上层业务逻辑决定如何应对
- 在业务入口(如 Controller、Service 方法)做统一捕获,转为用户友好的提示或系统级错误码
- 涉及资源操作(文件、连接、流)时,配合 try-with-resources 自动释放,避免泄漏
示例:
public String readConfig(String path) throws IOException {
// 不在这里 catch,因为读配置失败的具体应对策略由调用方决定
return Files.readString(Path.of(path));
}
// 调用处(如 Web 接口)
@GetMapping("/config")
public ResponseEntity getConfig() {
try {
return ResponseEntity.ok(readConfig("app.conf"));
} catch (IOException e) {
log.warn("配置文件读取失败", e);
return ResponseEntity.status(500).body("配置服务暂时不可用");
}
}
什么时候不该用受检异常?
如果一个异常本质上反映的是编程错误(比如参数校验失败、状态非法),就该用非受检异常(IllegalArgumentException、IllegalStateException)。强行用受检异常反而会让调用方疲于应付,违背“可恢复”初衷。另外,现代框架(如 Spring)常将部分受检异常(如 SQLException)包装为非受检异常,也是为了简化 API 使用。










