惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
C
CERT Recently Published Vulnerability Notes
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Latest news
Latest news
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Hacker News
The Hacker News
Malwarebytes
Malwarebytes
G
GRAHAM CLULEY
P
Privacy International News Feed
Spread Privacy
Spread Privacy
S
Schneier on Security
V
V2EX
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
Cisco Talos Blog
Cisco Talos Blog
T
Threat Research - Cisco Blogs
罗磊的独立博客
B
Blog RSS Feed
Stack Overflow Blog
Stack Overflow Blog
F
Fortinet All Blogs
Recent Announcements
Recent Announcements
S
Securelist
阮一峰的网络日志
阮一峰的网络日志
SecWiki News
SecWiki News
aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享
C
Cybersecurity and Infrastructure Security Agency CISA
IT之家
IT之家
Schneier on Security
Schneier on Security
MyScale Blog
MyScale Blog
李成银的技术随笔
Know Your Adversary
Know Your Adversary
人人都是产品经理
人人都是产品经理
I
Intezer
Vercel News
Vercel News
有赞技术团队
有赞技术团队
博客园 - 三生石上(FineUI控件)
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
F
Fox-IT International blog
V
Visual Studio Blog
Simon Willison's Weblog
Simon Willison's Weblog
Cyberwarzone
Cyberwarzone
博客园 - Franky
S
Secure Thoughts
L
LINUX DO - 热门话题
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Register - Security
The Register - Security
T
Threatpost
博客园 - 司徒正美

阮一峰的网络日志

科技爱好者周刊(第 397 期):财富正在向 AI 集中 科技爱好者周刊(第 397 期):财富正在向 AI 集中 科技爱好者周刊(第 396 期):互联网通信的替代方案 科技爱好者周刊(第 396 期):互联网通信的替代方案 - 阮一峰的网络日志 科技爱好者周刊(第 395 期):软件开发的第三种方式 - 阮一峰的网络日志 科技爱好者周刊(第 395 期):软件开发的第三种方式 科技爱好者周刊(第 394 期):第二次 API 开放浪潮 科技爱好者周刊(第 393 期):脑腐状态 科技爱好者周刊(第 392 期):axios 投毒与好莱坞式骗术 科技爱好者周刊(第 391 期):AI 的贫富分化 科技爱好者周刊(第 390 期):没有语料,大模型就是智障 套壳中国大模型撑起500亿美元估值?扒一扒 Cursor 的"套壳"疑云 科技爱好者周刊(第 389 期):未来如何招聘程序员 科技爱好者周刊(第 388 期):测试是新的护城河 零安装的"云养虾":ArkClaw 使用指南 科技爱好者周刊(第 387 期):你是领先的 科技爱好者周刊(第 386 期):当外卖员接入 AI 字节全家桶 Seed 2.0 + TRAE 玩转 Skill 科技爱好者周刊(第 385 期):马斯克害怕中国车企吗? 智谱旗舰 GLM-5 实测:对比 Opus 4.6 和 GPT-5.3-Codex 科技爱好者周刊(第 384 期):为什么软件股下跌 科技爱好者周刊(第 383 期):你是第几级 AI 编程 Kimi 的一体化,Manus 的分层 科技爱好者周刊(第 382 期):独立软件的黄昏 AI native Workspace 也许是智能体的下一阶段 科技爱好者周刊(第 381 期):中国 AI 大模型领导者在想什么 科技爱好者周刊(第 380 期):为什么人们拥抱"不对称收益" 科技爱好者周刊(第 379 期):《硅谷钢铁侠》摘录 我如何用 AI 处理历史遗留代码:MiniMax M2.1 升级体验 科技爱好者周刊(第 378 期):预测是新的互联网热点 科技爱好者周刊(第 377 期):14万美元的贫困线 科技爱好者周刊(第 376 期):太空数据中心的争议 科技爱好者周刊(第 375 期):一扇门的 Bug 终于有人做了 Subagent,TRAE 国内版 SOLO 模式来了 科技爱好者周刊(第 374 期):6GHz 的问题 VS Code 使用国产大模型 MiniMax M2 教程 科技爱好者周刊(第 373 期):数据模型是新产品的核心 国产大模型接入 Claude Code 教程:以 Doubao-Seed-Code 为例 科技爱好者周刊(第 372 期):软件界面如何设计 大模型比拼:MiniMax M2 vs GLM 4.6 vs Claude Sonnet 4.5 科技爱好者周刊(第 371 期):一个乐观主义者的专访 科技爱好者周刊(第 370 期):正确的代码高亮 科技爱好者周刊(第 369 期):Tim 与罗永浩的对谈 科技爱好者周刊(第 368 期):不要这样管理软件团队 一天之内,智谱和 Anthropic 都发了最强编程模型 科技爱好者周刊(第 367 期):Nano Banana 的几个妙用 科技爱好者周刊(第 366 期):旧金山疯狂的 AI 广告 科技爱好者周刊(第 365 期):流量变现正在崩塌 科技爱好者周刊(第 364 期):最难还原的魔方 科技爱好者周刊(第 363 期):最好懂的神经网络解释 科技爱好者周刊(第 362 期):GitHub 工程师谈系统设计 科技爱好者周刊(第 361 期):暗网 Tor 安全吗? 科技爱好者周刊(第 360 期):Dan Wang 的新书 科技爱好者周刊(第 359 期):Palantir 值得关注 科技爱好者周刊(第 358 期):如何拯救一家濒临倒闭的创业公司 科技爱好者周刊(第 357 期):稳定币的博弈 科技爱好者周刊(第 356 期):公司强推 AI 编程,我该怎么办 科技爱好者周刊(第 355 期):两本《芯片战争》 科技爱好者周刊(第 354 期):8000mAh 手机电池,说明了什么? 科技爱好者周刊(第 353 期):苹果的"液态玻璃"是为了 AR 科技爱好者周刊(第 352 期):Bug 追踪系统的正确样子 科技爱好者周刊(第 351 期):GitHub Issues(几乎)是最好的笔记应用 科技爱好者周刊(第 350 期):Java 三十周年 科技爱好者周刊(第 349 期):神经网络算法的发明者 科技爱好者周刊(第 348 期):李飞飞,从移民到 AI 明星 科技爱好者周刊(第 347 期):冷启动的破解之道 科技爱好者周刊(第 346 期):未来就是永恒感的丧失 科技爱好者周刊(第 345 期):HDMI 2.2 影音可能到头了 科技爱好者周刊(第 344 期):制造业正在"零工化" 科技爱好者周刊(第 343 期):如何阻止 AI 爬虫 科技爱好者周刊(第 342 期):面试的 AI 作弊----用数字人去面试 科技爱好者周刊(第 341 期):低代码编程,恐怕不会成功 科技爱好者周刊(第 340 期):技术炒作三十年 科技爱好者周刊(第 339 期):代币是什么 科技爱好者周刊(第 338 期):重新思考 6G 科技爱好者周刊(第 337 期):互联网创业几乎没了 科技爱好者周刊(第 336 期):面对 AI,互联网正在衰落 科技爱好者周刊(第 335 期):年底的未来已来 科技爱好者周刊(第 334 期):年终笔记四则 科技爱好者周刊(第 333 期):一切都要支付两次 科技爱好者周刊(第 332 期):西蒙·威利森的年终总结,梁文锋的访谈 科技爱好者周刊(第 331 期):你可能是一个 NPC 科技爱好者周刊(第 330 期):李开复梳理人工智能 科技爱好者周刊(第 329 期):示意图利器 D2 科技爱好者周刊(第 328 期):AI 模型不是一门好生意 科技爱好者周刊(第 327 期):没有链接的互联网 科技爱好者周刊(第 326 期):世界没有那么多财富 科技爱好者周刊(第 325 期):VS Code 编辑器的下一站是 Zed? 科技爱好者周刊(第 324 期):人类已知的最大质数 科技爱好者周刊(第 323 期):技术公司的口号比拼 科技爱好者周刊(第 322 期):内容行业的内幕 科技爱好者周刊(第 321 期):傅盛回忆录 科技爱好者周刊(第 320 期):乒乓仓 科技爱好者周刊(第 319 期):如何拍出爆款视频 科技爱好者周刊(第 318 期):创业咖啡馆的记忆 科技爱好者周刊(第 317 期):驴子、老虎和狮子的寓言 科技爱好者周刊(第 316 期):你一生的故事 科技爱好者周刊(第 315 期):一份谷歌离职报告 科技爱好者周刊(第 314 期):《黑神话:悟空》可以产业化吗? 科技爱好者周刊(第 313 期):如果新加坡没有空调
错误处理:异常好于状态码
阮一峰 · 2025-10-22 · via 阮一峰的网络日志

错误处理有不同的方式。

JavaScript 和 Python 是抛出异常, Rust 语言是变相抛出异常。

C 语言和 Go 语言则是返回一个错误值,你必须判断该值是否为 -1 或空值。

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

前不久,我读到一篇多年前的文章,明确提出抛出异常好于返回状态码。他的理由很有说服力,文章好像还没有中译,我就翻译出来了。

异常与返回状态码

作者:内德·巴切尔德(Ned Batchelder)

原文网址:nedbatchelder.com

在软件中,错误处理有两种方式:抛出异常(throwing exceptions)和返回状态码(returning status codes)。

几乎所有人都认为异常是更好的处理方式,但有些人仍然更喜欢返回状态码。本文解释为什么异常是更好的选择。

一、代码干净

异常可以让你在大部分代码中省去错误处理步骤。它会自动通过不捕捉异常的层,向上传递。你因此可以编写完全没有错误处理逻辑的代码,这有助于保持代码的简洁易读。

让我们比较一下,编写同一个简单函数的两种方法。

先是返回状态码。


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;
}

上面示例中,必须判断DoThing1(a)DoThing2(b)的返回值是否正常,才能进行下一步。

如果是抛出异常,就不需要中间的错误判断了。


void DoSomething(int a, int b)
{
    DoThing1(a);
    DoThing2(b);
}

这只是最简单的情况,如果遇到复杂的场景,状态码带来的噪音会更严重,异常则可以保持代码的整洁。

二、有意义的返回值

状态码会占用宝贵的返回值,你不得不增加代码,判断返回值是否正确。

有些函数本来只需要返回一个正常值,现在不得不增加返回错误的情况。随着时间的推移,代码量不断增长,函数变得越来越大,返回值也越来越复杂。

比如,很多函数的返回值是有重载的:"如果失败,则返回 NULL",或者失败返回 -1。结果就是每次调用这个方法,都需要检查返回值是否是 NULL 或 -1。如果函数后来增加新的错误返回值,则必须更新所有调用点。

如果是抛出异常,那么函数就总是成功的情况下才返回,所有的错误处理也可以简化放在一个地方。

三、更丰富的错误信息

状态码通常是一个整数,能够传递的信息相当有限。假设错误是找不到文件,那么是哪一个文件呢?状态码无法传递那么多信息。

返回状态码的时候,最好记录一条错误消息,放在专门的错误日志里面,调用者可以从中获取详细信息。

异常完全不同,它是类的实例,因此可以携带大量信息。由于异常可以被子类化,不同的异常可以携带不同的数据,从而形成非常丰富的错误消息体系。

四、可以处理隐式代码

某些函数无法返回状态码。例如,构造函数就没有显式的返回值,因此无法返回状态码。还有一些函数(比如析构函数)甚至无法直接调用,更不用说返回值了。

这些没有返回值的函数,如果不使用异常处理,你不得不想出其他方法来给出错误信息,或者假装这些函数不会失败。简单的函数或许可以做到无故障,但代码量会不断增长,失败的可能性也随之增加。如果没有办法表达失败,系统只会变得更加容易出错,也更加难以捉摸。

五、错误的可见性

考虑一下,如果程序员疏忽了,没有写错误处理代码,会发生什么情况?

如果返回的状态码没有经过检查,错误就不会被发现,代码将继续执行,就像操作成功一样。代码稍后可能会失败,但这可能是许多步操作之后的事情,你如何将问题追溯到最初错误发生的地方?

相反的,如果异常未被立刻捕获,它就会在调用栈中向上传递,要么到达更高的 catch 块,要么到达顶层,交给操作系统处理,操作系统通常会把错误呈现给用户。这对程序是不好的,但错误至少是可见的。你会看到异常,能够判断出它抛出的位置,以及它应该被捕获的位置,从而修复代码。

这里不讨论错误未能报出的情况,这种情况无论是返回状态码还是抛出异常,都没用。

所以,对于报出的错误没有被处理,可以归结为两种情况:一种是返回的状态码会隐藏问题,另一种是抛出异常会导致错误可见。你会选择哪一种?

六、反驳

著名程序员 Joel Spolsky 认为,返回状态码更好,因为他认为异常是一种糟糕得多的 goto 语句。

"异常在源代码中是不可见的。阅读代码块时,无法知道哪些异常可能被抛出,以及从哪里抛出。这意味着即使仔细检查代码,也无法发现潜在的错误。"

"异常为一个函数创建了太多可能的出口。要编写正确的代码,你必须考虑每一条可能的代码路径。每次调用一个可能抛出异常的函数,但没有立即捕获异常时,函数可能突然终止,或者出现其他你没有想到的代码路径。"

这些话听起来似乎很有道理,但如果改为返回状态码,你就必须显式地检查函数每一个可能的返回点。所以,你是用显式的复杂性换取了隐式的复杂性。这也有缺点,显式的复杂性会让你只见树木不见森林,代码会因此变得杂乱无章。

当面临这种显式复杂性时,程序员会写得不胜其烦,最后要么用自定义的方法隐藏错误处理,要么索性省略错误处理。

前者隐藏错误处理,只会将显式处理重新变为隐式处理,并且不如原始的 Try 方法方便和功能齐全。后者省略错误处理更糟糕,程序员假设某种错误不会发生,从而埋下风险。

七、总结

返回状态码很难用,有些地方根本无法使用。它会劫持返回值。程序员很容易不去写错误处理代码,从而在系统中造成无声的故障。

异常优于状态码。只要你的编程语言提供了异常处理工具,请使用它们。

(完)