异常链与多重捕获
异常链保留原始异常信息,多重捕获简化多异常处理。
异常链
什么是异常链
异常链是在包装异常时保留原始异常(cause),便于追踪错误根源。
Java
try {
// 原始异常
int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
// 包装异常,保留原始异常作为cause
throw new BusinessException("计算失败", e);
}
构造异常链
使用带Throwable参数的构造方法。
Java
// 方式1:构造时传入cause
try {
readFile();
} catch (IOException e) {
throw new BusinessException("业务处理失败", e); // e作为cause
}
// 方式2:使用initCause
try {
connect();
} catch (SQLException e) {
BusinessException ex = new BusinessException("连接失败");
ex.initCause(e); // 设置cause
throw ex;
}
获取cause信息
Java
try {
// ...
} catch (BusinessException e) {
// 获取包装异常信息
String message = e.getMessage(); // "业务处理失败"
// 获取原始异常
Throwable cause = e.getCause();
if (cause != null) {
String causeMsg = cause.getMessage(); // 原始异常消息
cause.printStackTrace(); // 原始异常堆栈
}
}
异常链堆栈输出
Java
public void method() {
try {
int x = 10 / 0;
} catch (ArithmeticException e) {
throw new BusinessException("计算错误", e);
}
}
// 输出堆栈
BusinessException: 计算错误
at Test.method(Test.java:5)
Caused by: ArithmeticException: / by zero
at Test.method(Test.java:3)
"Caused by"显示原始异常信息,便于定位根本原因。
异常链使用场景
| 场景 | 说明 |
|---|---|
| 业务层包装 | 将技术异常转换为业务异常 |
| API封装 | 对外暴露统一异常类型 |
| 分层架构 | 每层添加上下文信息 |
| 错误追踪 | 保留完整错误链 |
Java
// 分层异常链示例
public void serviceMethod() throws ServiceException {
try {
daoMethod();
} catch (DaoException e) {
throw new ServiceException("服务层处理失败", e);
}
}
public void daoMethod() throws DaoException {
try {
jdbcOperation();
} catch (SQLException e) {
throw new DaoException("数据访问失败", e);
}
}
多重捕获
Java 7+多重捕获语法
一个catch块捕获多种异常类型,使用|分隔。
Java
// 传统方式:多个catch块
try {
// ...
} catch (IOException e) {
handleException(e);
} catch (SQLException e) {
handleException(e);
}
// 多重捕获:一个catch块(Java 7+)
try {
// ...
} catch (IOException | SQLException e) {
handleException(e); // 同一种处理方式
}
多重捕获优势
Java
// 简化重复代码
try {
connect();
query();
} catch (IOException | SQLException | ClassNotFoundException e) {
logger.error("操作失败", e);
throw new BusinessException("系统异常", e);
}
多重捕获规则
- 异常类型不能有继承关系(不能同时捕获Exception和IOException)
- catch块内异常变量是final的(不能重新赋值)
- 多种异常共享同一种处理逻辑
Java
// 错误:类型有继承关系
try {
// ...
} catch (IOException | Exception e) { // 编译错误
// IOException是Exception子类
}
// 正确:类型无继承关系
try {
// ...
} catch (IOException | SQLException e) { // 正确
// IOException和SQLException无继承关系
}
异常链与多重捕获结合
实际应用示例
Java
public void processFile(String path) throws BusinessException {
try {
FileReader reader = new FileReader(path);
// 处理文件
} catch (FileNotFoundException | IOException e) {
// 多重捕获,统一包装
throw new BusinessException("文件处理失败", e);
}
}
分层架构应用
Java
public class UserService {
public User getUser(Long id) throws ServiceException {
try {
return userDao.findById(id);
} catch (SQLException | IOException e) {
// 多重捕获技术异常
throw new ServiceException("获取用户失败", e);
}
}
public void updateUser(User user) throws ServiceException {
try {
userDao.update(user);
} catch (SQLException | IOException e) {
throw new ServiceException("更新用户失败", e);
}
}
}
获取异常链信息
打印完整异常链
Java
try {
// ...
} catch (Exception e) {
e.printStackTrace(); // 自动打印Caused by链
}
// 输出:
ServiceException: 服务层错误
at Service.method()
Caused by: DaoException: DAO层错误
at Dao.method()
Caused by: SQLException: 数据库错误
at Jdbc.operation()
手动遍历异常链
Java
public void printExceptionChain(Throwable e) {
while (e != null) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
e = e.getCause(); // 获取下一层异常
}
}
// 使用
try {
// ...
} catch (Exception e) {
printExceptionChain(e);
// ServiceException: 服务层错误
// DaoException: DAO层错误
// SQLException: 数据库错误
}
要点总结
- 异常链通过cause保留原始异常信息
- 构造异常时传入cause:new Exception(msg, cause)
- getCause()获取原始异常
- printStackTrace()自动显示Caused by链
- 异常链用于分层架构、业务包装
- 多重捕获用
|分隔多种异常类型(Java 7+) - 多重捕获类型不能有继承关系
- catch变量是final的,不能重新赋值
- 多重捕获简化重复处理代码
- 异常链和多重捕获可结合使用
📝 发现内容有误?点击此处直接编辑