必知的8个异常处理误区
引言
在Java开发中,异常处理看似简单,却隐藏着无数“暗坑”。一个未被妥善处理的异常可能导致服务雪崩、数据不一致,甚至引发安全漏洞。本文深入分析新手常见的8个异常处理误区,并提供实战解决方案,助你写出更健壮的代码。
捕获Throwable或Error
错误示例:
try {
// 业务代码
} catch (Throwable e) { // 包括 Error
e.printStackTrace();
}
问题:
- Error 表示 JVM 无法处理的严重问题(如,OutOfMemoryError),捕获后可能导致程序无法正常终止;
- 可能掩盖真正需要关注的业务异常。
正确做法:
try {
// 业务代码
} catch (SpecificException e) { // 明确捕获具体异常
handleException(e);
} catch (Exception e) { // 通用异常兜底
log.error("Unexpected error", e);
}
忽略异常(空 catch 块)
错误示例:
try {
FileInputStream fis = new FileInputStream("data.txt");
} catch (FileNotFoundException e) {
// 空 catch 块,假装问题不存在
}
后果:
- 文件示找到时程序静默失败,后续操作可能引发更隐蔽的异常;
- 难以定位根原因,增加调试成本。
改进方案:
try {
FileInputStream fis = new FileInputStream("data.txt");
} catch (FileNotFoundException e) {
log.error("文件不存在", e);
throw new BusinessException("数据文件缺失,请检查配置", e); // 封装并传递
}
过度捕获异常
错误示例:
try {
userService.save(user);
orderService.createOrder(user);
} catch (Exception e) { // 捕获所有异常
rollbackTransaction();
}
问题:
- 可能意外捕获 RuntimeException(如,NullPointerException),掩盖代码逻辑错误;
- 无法针对不同异常实施差异化处理。
优化策略:
try {
userService.save(user);
orderService.createOrder(user);
} catch (OptimisticLockingFailureException e) {
retryTransaction(); // 乐观锁冲突重试
handleConstraintViolation(e); // 处理数据约束问题
log.error("未知异常", e);
rollbackTransaction();
}
finally 块中使用 return
错误示例:
public int calculate() {
try {
return 1 / 0; // 抛出 ArithmeticException
} finally {
return 0;
}
}
后果:
- 掩盖原始异常,返回错误数据;
- 调试时无法发现真实的异常堆栈。
正确写法:
public int calculate() throws ArithmeticException {
try {
return 1 / 0;
} finally {
cleanupResources(); // 仅释放资源,不返回值
}
}
滥用异常控制流程
错误示例:
try {
User user = userRepository.findById(id);
} catch () {
createNewUser(id);
}
问题:
- 异常处理成本远高于正常判断逻辑;
- 破坏代码可读性。
改进方案:
Optional<User> userOpt = userRepository.findById(id);
if (userOpt.isPresent()) {
return userOpt.get();
} else {
return createNewUser(id); // 正常流程处理
}
不关闭资源的 try-with-resources
错误示例:
BufferReader br = new BufferReader(new FileReader("data.txt"));
try {
String line = br.readLine();
//...
} finally {
if (br != null) {
br.close(); // 手动关闭易遗漏
}
}
隐患:
- 资源未关闭可能导致内存泄漏或文件句柄耗尽。
正确做法:
try (BufferReader br = new BufferReader(new FileReader("data.txt"))) {
String line = br.readLine();
//...
} // 自动关闭
忽略异常链(丢失根因)
错误示例:
try {
parseData(json);
} catch (JsonParseException e) {
throw new BusinessException("数据解析失败"); // 丢失原始异常
}
后果:
- 日志中无法追踪原始异常堆栈,增加排查难度。
改进方案:
try {
parseData(json);
} catch (JsonParseException e) {
throw new BusinessException("数据解析失败", e); // 传递原始异常
}
过度自定义异常类型
错误示例:
// 自定义几十种异常类型,但处理方式相同
throw new UserNotFoundInCacheException();
throw new UserNotExistInDBException();
问题:
- 增加维护成本,降低代码可读性;
- 可能导致重复处理逻辑。
优化建议:
// 按处理方式分类异常
throw new NotFoundException("用户不存在", EntityType.USER);
throw new NotFoundException("订单不存在", EntityType.ORDER);

浙公网安备 33010602011771号