大家好,我是大华。 昨天被迫帮同事改bug,看到他的代码我差点心梗:
java
try {
// 业务代码NN行
} catch (Exception e) {
e.printStackTrace();
}
这异常处理写得,真是老太太钻被窝------哈哈! 同事还说:"代码能跑就行,要啥自行车啊?"
但问题是,这种写法就像是在代码里埋了颗地雷,说不准什么时候就炸了。 所以这篇文章我把从阿里大神那偷师的9个异常处理分享给大家,保准让你的代码更健壮!
1. 别抓了异常又扔掉!
这种就是抓了异常又不处理的:
java
// 错误示范
try {
userService.save(user);
} catch (IOException e) {
e.printStackTrace();
}
正确做法:
java
try {
userService.save(user);
} catch (IOException e) {
log.error("保存用户信息失败,用户ID:{}", user.getId(), e);
throw new BusinessException("保存用户失败,请重试");
}
记日志是为了排查问题,重抛异常是让上游知道到底是哪里出错了!
2. 精确捕获异常
很多新手爱用Exception
一把梭:
java
// 错误示范
try {
// 各种操作
} catch (Exception e) { // 抓得太宽了
// 处理异常
}
正确写法:
java
try {
// 业务代码
} catch (FileNotFoundException e) {
// 处理文件不存在
} catch (IOException e) {
// 处理IO问题
} catch (SQLException e) {
// 处理数据库问题
}
不同的异常不同的处理方式!
3. finally里不要乱写!
这个代码看的让人血压直接升高:
java
try {
// 业务代码
return true;
} finally {
return false; // 居然在finally里返回!
}
finally里只做清理工作:
java
InputStream input = null;
try {
input = new FileInputStream("file.txt");
// 处理文件
} finally {
if (input != null) {
try {
input.close(); // 只做资源清理
} catch (IOException e) {
log.warn("关闭流失败", e);
}
}
}
4. 抛异常要带上原始信息!
这样抛异常等于没抛:
java
// 错误示范
try {
// 代码
} catch (IOException e) {
throw new BusinessException("操作失败"); // 原始异常信息丢了!
}
应该包装原始异常:
java
try {
// 代码
} catch (IOException e) {
throw new BusinessException("文件操作失败", e); // 把e传进去
}
这样堆栈信息才不会断!
5. 别用异常做流程控制!
这是我见过最骚的操作:
java
// 错误示范
try {
while (true) {
// 靠异常跳出循环!
list.get(index);
index++;
}
} catch (IndexOutOfBoundsException e) {
// 循环结束
}
正确写法:
java
for (String item : list) {
// 正常循环处理
// 有问题跳出即可
}
// 或者
for (int i = 0; i < list.size(); i++) {
// 也是正常的
// 有问题跳出即可
}
异常处理其实还是很耗性能的,不能啥都用异常来抛出!
6. 自定义异常更有意义!
别老是抛RuntimeException
:
java
// 不太好的做法
if (user == null) {
throw new RuntimeException("用户不存在");
}
自定义异常更清晰:
java
// 先定义业务异常
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
// 使用时
if (user == null) {
throw new UserNotFoundException("用户ID不存在:" + userId);
}
这样一看就知道是什么问题!
7. 异常信息要能看懂!
这种异常信息看了想冒火:
java
// 错误示范
throw new Exception("出错啦");
throw new Exception("系统错误");
好的异常信息应该这样:
java
// 好的异常信息应该包含关键信息
throw new ValidationException(
String.format("用户手机号格式错误:%s,请输入11位数字", phoneNumber)
);
throw class BalanceNotEnoughException(
String.format("用户余额不足,用户ID:%s,当前余额:%.2f,需要金额:%.2f",
userId, currentBalance, requiredAmount)
);
看到异常就知道具体什么问题,bug该怎么修!
8. 别忘了异常的性能!
异常处理是昂贵的,别在频繁调用的地方去使用:
java
// 常用的数据类型转换(错误示范)
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return defaultValue;
}
对于可预见的错误,应该先检查:
java
// 先检查再转换,性能更好
if (str == null || !str.matches("\\d+")) {
return defaultValue;
}
return Integer.parseInt(str);
9. 统一异常处理!
最后一点,也是最重要的一点:统一处理异常。
尽量不要在代码里到处try-catch:
java
// Controller中的方法
@PostMapping("/create")
public Result createUser(@RequestBody User user) {
try {
userService.create(user);
return Result.success();
} catch (UserExistException e) {
log.warn("用户已存在", e);
return Result.error("用户已存在");
} catch (Exception e) {
log.error("创建用户失败", e);
return Result.error("系统繁忙");
}
}
用@ControllerAdvice统一处理:
java
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
@ResponseBody
public Result handleBusinessException(BusinessException e) {
log.warn("业务异常", e);
return Result.error(e.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseBody
public Result handleException(Exception e) {
log.error("系统异常", e);
return Result.error("系统繁忙,请稍后重试");
}
}
这样代码清爽多了,异常处理逻辑都在一起!
总结一下
好的异常处理不是炫技,而是让你的代码:
- 更健壮:不会轻易崩溃
- 更可读:异常信息清晰明了
- 易维护:问题定位快
这9条,不是为了看起来专业,而是为了:线上出问题时,你能第一时间定位,而不是在那干瞪眼。 把这 9 条做成团队规范,省下的不只是时间,还有头发。 ------ 写给每一个被异常坑过的 Java 程序员
我是大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!
📌往期精彩
《Elasticsearch 太重?来看看这个轻量级的替代品 Manticore Search》
《只会写 Mapper 就敢说会 MyBatis?面试官:原理都没懂》
《别学23种了!Java项目中最常用的6个设计模式,附案例》