190. Java 异常 - 绕过 Catch or Specify 要求?你真的想好了吗?
在 Java 中,**受检异常(Checked Exception)**必须用 try-catch 或 throws 明确处理,这是所谓的:
🎯 Catch or Specify Requirement(捕获或声明要求)
但是有些开发者认为这一要求太“啰嗦”,于是选择绕过它,方法就是:
❗ 用 “Unchecked Exception” 代替 “Checked Exception”
🚨 什么是 Unchecked Exception?
我们前面讲过,**运行时异常(RuntimeException 及其子类)**是不受强制捕获要求的,也就是说:
public void readFile(String filename) {
throw new IllegalArgumentException("文件名非法!");
}
你写成上面这样是完全可以编译通过的,不需要写 throws 或 try-catch,因为 IllegalArgumentException 是 unchecked exception。
🔍 为什么有人要这么做?
有些程序员觉得:
- 受检异常写起来太麻烦,污染了代码结构
- 经常忘记处理异常,干脆不写
- 处理了也只是在
catch里打个log,没实际意义
所以他们把原本可能抛出 IOException, SQLException 的方法,改成抛出 RuntimeException 子类。
🙅♂️ 这真的好吗?
⚠️ 一般来说,不推荐这么做,原因如下:
1️⃣ 隐藏了程序应有的健壮性
受检异常的意义就是:提醒开发者这个地方可能出错,需要注意!
如果你用 unchecked exception 替代:
public void saveData() {
throw new RuntimeException("数据库出错了");
}
这段代码在使用时根本不会提示调用者它可能出错,调用者也可能完全不处理异常,导致程序突然崩溃。
2️⃣ 不利于编译期排查错误
使用受检异常时,编译器可以强制你处理异常,帮助你更早发现潜在问题。
用 unchecked exception,等于是说:“我懒得告诉你这会错”,结果可能是用户在运行中才发现程序崩了。
✅ 那什么时候可以用 Unchecked Exception?
这其实是个有争议的话题,在一些场景下,使用运行时异常是合理的,例如:
✅ 条件一:这是一个程序逻辑错误,不应恢复
比如参数为 null,是开发者错误传参导致,不应该强行处理:
public void setAge(Integer age) {
if (age == null || age < 0) {
throw new IllegalArgumentException("年龄必须为正数!");
}
}
✅ 条件二:你愿意在文档中清晰注明异常含义
如果你仍然选择使用 RuntimeException,请在方法说明中清楚注明可能抛出异常的类型和触发条件。
- “受检异常就像交通标志牌——麻烦但必要。”
- “绕过异常捕获就像关掉了火警报警器,可能更安静,但出事时代价更大。”
- “不是所有的错误都该你‘硬撑’,该说我可能出错的地方,就要诚实说出来。”
✅ 小结:要不要绕过 Catch or Specify?
| 场景 | 建议使用异常类型 |
|---|---|
| 文件未找到、网络超时 | ✅ Checked Exception |
| 参数非法、状态错误 | ⚠️ RuntimeException |
| 系统崩溃、内存溢出 | ❌ 不主动处理(Error) |