Java异常常见误区有哪些
在Java异常处理中,开发者常因对机制理解不深而陷入一些误区。以下是最常见的误区及正确实践,结合代码示例说明:
一、捕获异常却不处理(吞掉异常)
❌ 错误示例
try {
int a = 1 / 0;
} catch (Exception e) {
// 什么都不做
}
问题
- 异常信息丢失
- 问题难以排查
- 程序在错误状态下继续运行
✅ 正确做法
catch (Exception e) {
log.error("计算失败", e);
throw e; // 或包装后抛出
}
二、捕获 Throwable / Exception 过于宽泛
❌ 错误示例
try {
doSomething();
} catch (Exception e) {
// 捕获所有异常
}
问题
- 会捕获
NullPointerException、RuntimeException - 掩盖真正的程序错误
- 不利于定位问题
✅ 正确做法
catch (IOException e) {
// 只处理可预期的异常
}
三、用异常做正常流程控制
❌ 错误示例
try {
int num = Integer.parseInt(str);
} catch (NumberFormatException e) {
num = 0;
}
问题
- 异常是非正常流程
- 性能差
- 代码可读性低
✅ 正确做法
if (str != null && str.matches("\d+")) {
num = Integer.parseInt(str);
} else {
num = 0;
}
四、在 finally 中返回或抛异常
❌ 错误示例
try {
return 1;
} finally {
return 2; // 覆盖 try 的返回值
}
问题
finally中的return会覆盖 try / catch 的返回值- 可能掩盖异常
✅ 正确做法
int result;
try {
result = 1;
} finally {
// 只做资源释放
}
return result;
五、在 finally 中关闭资源但忽略异常
❌ 错误示例
finally {
fos.close(); // 可能抛 IOException
}
✅ 正确做法(Java 7+)
try (FileOutputStream fos = new FileOutputStream("a.txt")) {
fos.write(1);
}
六、把异常包装成 RuntimeException 却不保留原因
❌ 错误示例
catch (IOException e) {
throw new RuntimeException("error");
}
问题
- 原始异常信息丢失
- 排查困难
✅ 正确做法
throw new RuntimeException("IO error", e);
七、异常只打日志不抛出
❌ 错误示例
catch (Exception e) {
log.error("error", e);
}
问题
- 调用方不知道失败
- 程序状态不一致
✅ 正确做法
catch (Exception e) {
log.error("error", e);
throw e;
}
八、在构造函数中抛异常却不说明
❌ 错误示例
public User(String name) {
if (name == null) {
throw new IllegalArgumentException();
}
}
✅ 正确做法
throw new IllegalArgumentException("name must not be null");
九、误以为 catch 能捕获子线程异常
❌ 错误示例
try {
new Thread(() -> {
throw new RuntimeException();
}).start();
} catch (Exception e) {
// 捕获不到
}
✅ 正确做法
Thread t = new Thread(() -> {
throw new RuntimeException();
});
t.setUncaughtExceptionHandler((t1, e) -> log.error("error", e));
t.start();
十、滥用自定义异常
❌ 错误示例
class MyException extends Exception {}
class MyException2 extends Exception {}
问题
- 异常类爆炸
- 调用方难以处理
✅ 正确做法
- 精简异常体系
- 使用标准异常(
IllegalArgumentException、IllegalStateException)
总结速查表
| 误区 | 核心问题 |
|---|---|
| 吞异常 | 信息丢失 |
| 捕获太宽 | 掩盖错误 |
| 用异常控制流程 | 性能 + 可读性差 |
| finally return | 覆盖结果 |
| 不保留 cause | 排查困难 |
| 只 log 不抛 | 状态不一致 |
| 线程异常 | 捕获不到 |
| 滥用自定义异常 | 设计复杂 |
如果你愿意,我也可以:
- 给你一份 Java异常最佳实践清单
- 结合 Spring / 后端项目 讲常见坑
- 用 面试题形式 总结异常误区