✅ 核心速览:
| JDK 版本 | 关键特性 | 影响 |
|---|---|---|
| 1.0 (1996) | try-catch-finally、Checked Exception 强制机制 | 奠定 Java 异常体系基础 |
| 1.4 (2002) | 异常链(initCause()/getCause()) | 支持嵌套异常,调试能力飞跃 |
| 7 (2011) | try-with-resources、Multi-catch、Rethrow 类型推断 | 资源泄漏大幅减少,语法更简洁 |
| 8 (2014) | Lambda/Stream 普及 | Checked Exception 与函数式接口冲突,催生包装模式 |
| 9 (2017) | StackWalker API (JEP 259) | 替代 getStackTrace(),支持延迟计算、过滤、高性能栈遍历 |
| 14 (2020) | Helpful NullPointerExceptions (预览) | NPE 显示具体哪一步为 null |
| 15 (2020) | NPE 精准消息默认开启 | 无需 JVM 参数,生产环境直接可用 |
| 17 (2021) | SecurityManager 标记废弃 | 传统基于 SecurityManager 的异常拦截逐步淘汰 |
| 21 (2023) | 虚拟线程 (JEP 425)、Record/模式匹配稳定 | 异常传播模型优化;结构化并发提供新错误处理范式 |
| 22/23 (2024/2025) | 未命名模式/变量 (JEP 456/443)、外部内存 API | 进一步简化异常处理样板代码;底层错误处理更贴近系统级 |
异常类层次结构自 JDK 1.0 起保持稳定,演进主要集中在 语法糖、底层诊断 API、并发模型适配 三个方向。
1、基本定义
所有异常与错误的根类是 java.lang.Throwable,它仅有两个直接子类:
java.lang.Throwable
├── java.lang.Error ← 系统级严重错误
└── java.lang.Exception ← 程序可处理的异常
├── java.lang.RuntimeException ← 非检查异常(Unchecked)
└── (其他 Exception) ← 检查异常(Checked)
| 维度 | Error | Exception |
|---|---|---|
| 语义 | JVM 或底层资源发生不可恢复的故障 | 程序运行中可预见、可干预的异常状态 |
| 编译期检查 | 不强制处理(属于 Throwable 非 Exception) | 分为 Checked(强制处理)与 Unchecked(不强制) |
| 恢复可能 | 几乎不可能,通常需重启或人工介入 | 可通过重试、降级、用户提示等方式恢复 |
| 典型场景 | OOM、栈溢出、类链接失败、JVM 内部错误 | IO 失败、参数非法、空指针、业务校验失败 |
| 捕获建议 | 不建议业务代码捕获(仅用于全局监控/优雅退出) | 应针对性捕获并处理 |
💡 经典易混淆点:
ClassNotFoundException是 Checked Exception(反射时类不存在);而NoClassDefFoundError是 Error(编译时存在,运行时类加载失败,属于链接错误)。
2、Error 详解
2.1、常见子类
| 子类 | 触发条件 | 现代 JDK 应对建议 |
|---|---|---|
OutOfMemoryError | 堆/元空间/直接内存耗尽 | 配合 -XX:+HeapDumpOnOutOfMemoryError,使用 jcmd/MAT 分析 |
StackOverflowError | 递归过深或线程栈太小 | 检查递归逻辑;虚拟线程(JDK 21+)栈按需分配,风险降低 |
InternalError / UnknownError | JVM 自身缺陷或底层系统调用失败 | 升级 JDK,提交 Bug 报告 |
AssertionError | assert 断言失败(默认关闭) | 仅用于开发期自检,生产环境应关闭 -ea |
2.2、处理原则
- 不要捕获
Error做业务重试:JVM 状态已不可信,继续运行可能导致数据损坏。 - 全局兜底:可通过
Thread.setDefaultUncaughtExceptionHandler()记录日志、触发告警、优雅关闭进程。 - 监控集成:现代 APM 框架(如 Arthas、SkyWalking)通过
StackWalker或 JVMTI 拦截Error,而非业务代码catch。
3、Exception 详解
3.1、Checked vs Unchecked
| 类型 | 编译器行为 | 设计初衷 | 现代观点 |
|---|---|---|---|
| Checked | 必须 try-catch 或 throws | 强制开发者处理可恢复错误 | 易导致 API 污染、样板代码泛滥、与函数式编程冲突 |
Unchecked (RuntimeException) | 不强制处理 | 表示编程错误或严重业务违规 | Spring/Effective Java 推荐优先使用,API 更干净 |
Checked Exception 机制保留但不鼓励新增。JDK 自身也在逐步用
Unchecked替代历史 Checked 异常(如java.util.zip部分 API)。
3.2、常见 RuntimeException 子类
NullPointerException/IllegalArgumentException/IllegalStateExceptionIndexOutOfBoundsException/ArithmeticExceptionConcurrentModificationException/UnsupportedOperationException
3.3、自定义异常规范
// ✅ 推荐:继承 RuntimeException,提供完整构造链
public class BusinessException extends RuntimeException {
public BusinessException(String message) { super(message); }
public BusinessException(String message, Throwable cause) { super(message, cause); }
// 可附加业务码、上下文等字段
}
4、JDK 21+ 的关键改进
4.1、精准 NPE 消息(JDK 15+ 默认)
// 传统:NullPointerException
// JDK 21:NullPointerException: Cannot invoke "String.trim()" because "user.getName()" is null
- 实现原理:JVM 在字节码插入空值检查点,异常时携带精确路径。
- 性能影响:< 1%,生产环境强烈推荐保持开启。
4.2、StackWalker 替代传统栈遍历
// ❌ 旧方式(已不推荐)
Thread.currentThread().getStackTrace();
// ✅ JDK 9+ 推荐
StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
walker.forEach(frame -> System.out.println(frame.getClassName() + "." + frame.getMethodName()));
- 优势:按需计算、支持过滤、无
SecurityManager依赖、虚拟线程友好。 - 适用场景:APM、日志框架、权限校验、自定义异常上下文注入。
4.3、虚拟线程的异常传播
- 虚拟线程未捕获异常不会杀死载体平台线程,而是交由
UncaughtExceptionHandler。 - 结构化并发(
StructuredTaskScope,JDK 21 预览→JDK 23 标准)提供join()时聚合子任务异常的能力,替代传统Future.get()的阻塞异常处理。
4.4、模式匹配简化异常负载解析
// JDK 21+ switch 模式匹配
switch (ex) {
case BusinessException(String msg, int code) -> log.warn("Biz error: {} [{}]", msg, code);
case RuntimeException r -> log.error("Runtime error", r);
default -> log.error("Unknown", ex);
}
- 注:异常类本身仍不推荐直接解构,但配合
record异常负载时非常优雅。
5、异常处理最佳实践
| 场景 | 推荐做法 | 反模式 |
|---|---|---|
| 资源管理 | try (var conn = ds.getConnection()) { ... } | finally 中手动 close() |
| 异常包装 | throw new BizException("失败", e) | catch (Exception e) { throw new BizException(e.getMessage()); }(丢失堆栈) |
| 空值处理 | Objects.requireNonNull() / 可选值模式 | 依赖 NPE 异常控制流 |
| API 设计 | 优先 RuntimeException,文档说明语义 | 泛滥 Checked Exception,方法签名冗长 |
| 全局处理 | @RestControllerAdvice / Thread.setDefaultUncaughtExceptionHandler | 每个方法重复 try-catch |
| 日志记录 | log.error("上下文", e) | e.printStackTrace() 或吞掉异常 |
1293

被折叠的 条评论
为什么被折叠?



