Java异常链通过带Throwable cause参数的构造函数封装原始异常,自JDK 1.4起标准异常类均支持;自定义异常需显式调用super(message, cause);避免仅传message、吞掉异常或字符串拼接导致链断裂。

Java 异常链通过构造函数将原始异常(cause)封装进新异常,使调用栈中能追溯到最初出错的根源。关键在于使用支持 Throwable cause 参数的构造方法,并确保原始异常未被吞掉。
使用带 cause 的构造函数
从 Java 1.4 开始,所有标准异常类(如 RuntimeException、IOException)都提供接收 Throwable 类型 cause 的构造方法。这是建立异常链最直接、推荐的方式:
- 捕获原始异常后,用它作为 cause 创建并抛出新异常
- JVM 自动维护
getCause()链,并在打印堆栈时递归显示嵌套异常(从最外层到最内层) - 避免手动拼接消息或丢弃原始异常信息
示例:
try {FileInputStream fis = new FileInputStream("missing.txt");
} catch (FileNotFoundException e) {
throw new RuntimeException("配置文件加载失败", e); // e 作为 cause 传入
}
自定义异常需显式支持 cause
若编写自己的异常类,必须在构造函数中调用父类含 cause 的构造器,否则异常链会中断:
立即学习“Java免费学习笔记(深入)”;
- 继承
Exception或RuntimeException - 至少提供一个接收
String message, Throwable cause的构造方法 - 内部调用
super(message, cause)
示例:
public class ServiceException extends Exception {public ServiceException(String message, Throwable cause) {
super(message, cause); // 关键:委托给父类链式构造器
}
}
避免破坏异常链的常见错误
以下做法会切断或弱化异常链,导致原始异常丢失或难以诊断:
- 只传 message(如
new RuntimeException(e.getMessage())),原始异常对象未保留 - 捕获后仅记录日志却不重新抛出,或抛出无 cause 的新异常
- 在
catch块中对原始异常调用printStackTrace()后静默吞掉(即不 re-throw) - 用字符串拼接把多个异常信息揉在一起,丧失结构化 cause 关系
运行时检查与调试技巧
可通过代码验证异常链是否有效建立:
- 调用
exception.getCause()获取原始异常引用 - 用
exception.getStackTrace()和exception.getCause().getStackTrace()分别查看各层堆栈 - 打印异常时直接
e.printStackTrace(),JDK 默认递归输出 cause 链(从外到内,每层标有Caused by:)
不复杂但容易忽略


















