Error Handling: Exceptions Over Status Codes

Error Handling: Exceptions Over Status Codes
# 错误处理方式比较:异常 vs 状态码

错误处理在不同语言中有不同策略。

![image](https://blog.aitoearn.ai/content/images/2025/10/img_001-8.webp)

- **JavaScript** 和 **Python** 通常使用 **抛出异常**  
- **Rust** 通过 `Result` 类型变相实现异常处理  
- **C** 和 **Go** 语言通常 **返回错误值**,需要主动判断是否为 `-1` 或空值

我一直想知道,哪一种方式更好?

前不久,我读到一篇多年前的 [文章](https://nedbatchelder.com/text/exceptions-vs-status.html),作者 Ned Batchelder 明确提出:  
**抛出异常好于返回状态码**。  
他的观点很有说服力。文章似乎没有中译,我将其整理翻译如下。

---

## 异常与状态码

**作者**:Ned Batchelder  
**原文地址**:[nedbatchelder.com](https://nedbatchelder.com/text/exceptions-vs-status.html)

在软件开发中,错误处理主要有两种方式:

1. **抛出异常 (throwing exceptions)**
2. **返回状态码 (returning status codes)**

多数人认可异常更好,但仍有开发者偏爱状态码。下面解释为什么异常是更优的选择。

---

## 1. 代码更干净

异常让你省去大量显式的错误检查过程,它会**自动沿调用栈向上传递**,直到被捕获。  
因此,你的大部分代码不必插入重复的错误检查逻辑,从而更加简洁可读。

**状态码写法:**

STATUS DoSomething(int a, int b)

{

STATUS st;

st = DoThing1(a);

if (st != SGOOD) return st;

st = DoThing2(b);

if (st != SGOOD) return st;

return SGOOD;

}


必须在每一步后判断返回值是否正常,才能继续。

**异常写法:**

void DoSomething(int a, int b)

{

DoThing1(a);

DoThing2(b);

}


**总结**:  
在复杂场景下,状态码带来的噪音会成倍增加;异常则保持核心逻辑更清晰。

---

## 2. 保留有意义的返回值

- 状态码**占用返回值位置**,迫使你增加额外检查逻辑  
- 某些函数原本仅需返回正常值,现在要额外处理异常值(如返回 `NULL` 或 `-1`)  

长期来看:
- 代码量增多
- 返回值规则变复杂
- 每个调用方都必须同步更新错误判断逻辑

**异常优势**:
- 函数只在成功时返回正常值
- 错误处理集中在一个地方

---

## 3. 携带更多错误信息

- 状态码往往是简单整数,信息量有限  
- 如果错误是“找不到文件”,状态码无法告知**是哪一个文件**  
- 必须依赖独立日志来补充信息

异常是类实例,可以:
- 携带**具体数据**
- 使用子类区分多种错误类型
- 构建丰富的错误信息体系

---

## 4. 适用于无法返回值的函数

例如:
- **构造函数**没有显式返回值,难以用状态码返回错误
- **析构函数**等隐式调用函数,更无法返回状态码

若不用异常:
- 只能发明绕路机制传递错误
- 或假装这些函数永远不会失败(风险极大)

随着代码规模增长,失败概率升高,不暴露错误只会让系统更不可预测。

---

## 5. 错误可见性

如果**状态码**未被检查:
- 错误会被**静默吞掉**
- 代码继续执行,问题可能在下游才爆发,难以回溯

**异常**若未捕获:
- 会沿调用栈冒泡
- 最终可能由顶层捕获并交给 OS 显示错误
- 虽然对程序不是最优体验,但**至少错误是可见的**,可定位到抛出位置

**总结**:
- 状态码更易隐藏问题
- 异常让错误暴露出来

---

## 6. 反对意见及回应

著名程序员 **Joel Spolsky** 对异常的批评:
> - 异常是“不可见的 goto”,阅读代码时看不到哪些地方会抛异常  
> - 异常造成函数有太多可能的退出路径  
> - 要写正确代码,必须考虑每条路径  
> - 调用可能抛异常的函数时,若不立即捕获,控制流可能出现意外中断

**回应**:
- 采用状态码则必须**显式检查每个返回值**
- 你只是从**隐式复杂性**转为**显式复杂性**
- 显式复杂性会淹没主要逻辑,使代码更杂乱、更难维护
- 程序员常用自定义机制**隐藏显式错误处理**,这会退化成隐式处理,且比 `try` 不方便、不灵活
- 更糟的是,开发者可能**直接忽略错误处理**,埋下隐患

---

## 7. 结论

状态码:
- 笨重、易被忽略
- 占据返回值
- 在特定场景下不适用

异常:
- 信息丰富
- 控制流简洁
- 不易被悄然忽视

**如果语言支持异常,建议优先使用它们。**

---

> **相关延伸**  
> 现代跨平台 AI 内容创作工具(如 [AiToEarn 官网](https://aitoearn.ai/))在设计中,也依赖清晰的错误处理策略。  
> 这些系统集成 AI 生成、跨平台发布、分析与模型排名,用于在抖音、快手、微信公众号、B 站、小红书、Facebook、Instagram、LinkedIn、Threads、YouTube、Pinterest 和 X(Twitter)等平台高效分发内容。  
> 无论是软件工程还是 AI 工具,**让错误及时可见并妥善处理**,始终是构建健壮系统的关键。

Read more