关于滥用try/catch的疑问:用其规避临界崩溃是否为不良实践?
用try/catch规避临界崩溃算不算不良编码实践?
嘿,这个问题戳中了很多开发者的纠结点——既要防崩溃,又不想违反编码规范,我来给你掰扯清楚:不是所有用try/catch防崩溃的操作都是坏的,但滥用(尤其是用它替代本该做的前置检查)绝对是不良实践。
咱们结合你提到的除零、数组越界这两个具体例子来拆解:
一、先明确:可预见的异常,别用try/catch当“遮羞布”
像除零、数组越界这类问题,属于你提前就能预判到会发生的异常,这时候优先做前置逻辑检查,而不是靠try/catch兜底。
举个除零的反例(Python):
# 不好的写法:用try/catch掩盖本可以提前检查的问题 try: ratio = total / count except ZeroDivisionError: ratio = 0 # 甚至啥都不做,直接跳过
这种写法的问题在于:
- 逻辑不直观:别人读代码时,得看到catch块才反应过来“哦,这里可能会除零”,不如直接写判断清晰。
- 没必要的性能开销:虽然现代语言对异常处理做了优化,但异常的抛出和捕获本身还是比简单的条件判断要重。
- 容易掩盖隐患:如果后续有人修改
count的赋值逻辑,可能不知道这里有try/catch兜底,更容易引入逻辑漏洞。
正确的做法应该是前置检查:
# 好的写法:提前判断,逻辑一目了然 if count != 0: ratio = total / count else: ratio = 0 # 还可以加个日志:logger.warning("count为0,无法计算比率")
再看数组越界的例子(Java):
// 不好的写法:依赖try/catch处理可预见的索引问题 try { String item = items[index]; } catch (ArrayIndexOutOfBoundsException e) { item = null; }
换成前置检查的写法,逻辑清晰还能提前规避异常:
// 好的写法:先判断索引合法性 if (index >= 0 && index < items.length) { String item = items[index]; } else { item = null; logger.error("索引{}超出数组范围,数组长度为{}", index, items.length); }
二、这些场景下,用try/catch防崩溃是合理的
那什么时候该用try/catch?答案是处理那些你无法通过前置检查完全规避的“不可预见异常”:
- 外部依赖类异常:比如读取文件时,你提前检查了文件存在,但打开的瞬间文件被其他程序删除了;或者发起网络请求时,中途网络突然断开。这类情况你没法100%提前预判,用try/catch捕获并处理(比如提示用户“文件读取失败”“网络异常”)是合理的。
- 复杂解析类异常:比如解析JSON、XML时,可能存在各种格式错误,你不可能提前检查每个字段的合法性,这时候用try/catch包裹解析逻辑,统一处理“解析失败”的情况,比写一堆零散的检查要高效得多。
- 第三方库抛出的异常:如果调用的第三方库抛出了非运行时异常,而你又没法修改库的代码,这时候用try/catch捕获并做适配处理,也是必要的。
三、绝对要避免的坑:静默吞掉异常
如果你遇到异常时“什么都不做”,直接跳过,那这是最糟糕的做法——相当于把错误彻底掩盖了。比如:
try: ratio = total / count except ZeroDivisionError: pass # 啥都不做
这种代码会导致后续业务逻辑使用错误的默认值(或者根本没有值),引发更隐蔽的bug,而且出问题时你完全没有日志可以排查,比直接崩溃还难处理。
总结一下
- 对于可预见、可通过前置检查避免的异常(除零、数组越界):用try/catch兜底属于不良实践,优先做前置检查+明确的错误处理(日志、默认值)。
- 对于不可预见、无法提前规避的异常(IO、网络、复杂解析):用try/catch捕获并做合理处理(提示用户、记录日志)是良好的编码实践。
- 永远不要静默吞掉异常——崩溃不可怕,可怕的是崩溃了还不知道为什么。
内容的提问来源于stack exchange,提问作者Manuel Venè
相关产品推荐
相关产品推荐

