概念
异常:会改变程序正常执行流程的不常见的情况。
即程序未按期望的方式运行。
异常处理是系统复杂度最糟糕的来源之一。
处理特殊情况的代码比处理一般情况的代码更难编写,也比较难读,因为比较啰嗦,可能它比正常流程代码还多。
定义异常时通常不考虑如何处理异常。
很多程序语言包含这样的异常处理机制:底层代码抛出异常,外部代码捕获异常。
所有形式的异常都会增加复杂度。
异常处理本身可能会导致更多的异常:需考虑如何在异常处理时避免引入新的异常情况。
因为有些异常本身很难发生,因此很难测试处理这些异常的代码是否真的有效。
常见的异常情况
- 传入错误的参数
- 被调用的方法没能正常完成功能
- 丢包等
- 代码遇到了未定义的情况,无法处理
常见的处理异常的方式
- 继续进行流程
- 中止正进行的操作,向上报告异常
防御性代码会增加系统复杂度。
通过抛出异常,可以让开发者逃避处理某些情况 -> 需要让调用者自己去处理,增加了调用者的认知成本(复杂度)。
抛出异常很容易,处理异常很困难。
原则
尽量减少异常处理的地方(异常处理代码出现位置的数量)。
避免异常处理代码导致复杂度提升的4种方法
1. 修改功能定义,直接消除错误。
如某功能是删除指定元素。当指定元素不存在时,有2种处理方式:
- 报告异常:元素不存在,无法执行删除。
- 直接返回:元素不存在,可认为删除操作成功执行。
如某功能是获取指定字符串中,指定首尾索引之间的所有字符。当索引不合法(越界等)时,有2种处理方式:
- 报告异常:传入的参数索引值无效,无法获取指定字符集合
- 对传入的索引值进行合法化调整:不小于0、小于字符串长度、首索引不大于尾索引,再执行功能。
选2可以直接消除错误,进而也就不需要异常处理。
2. 屏蔽异常,让底层处理异常。
避免异常影响了太多的地方。
让底层处理异常的原因是:底层比高层更稳定,不容易变动。高层本身因为容易变动的原因就已经够复杂了,所以请不要再让它去关注异常处理了。
3. 在能捕获大部分异常的位置处理异常。
这种方法很容易想到,是非常直接的减少异常处理出现位置的方法。
例如某功能需要从好多处地方获得参数,可以不在各处判断参数的合法性,而是在获取到所有参数后,执行该功能前一齐判断。
4. 不触发异常,直接让系统崩溃(重启或退出)。
有些错误非常致命(通常也非常难出现),当这类错误真的发生时,简单的异常处理是无法处理该错误的,可能需要做很多操作。可认为这种情况下异常处理无法处理错误。
此时可以让系统崩溃,只要做好清晰的错误信息记录,方便后续修复错误就行。
程序运行时的一般情况和特殊情况
在编写代码时,有时为了极少出现的特殊情况需要写一堆的if去处理。
更好的做法是将普通情况设计成无需任何额外代码就能自动处理特殊情况的方式。
例如:在用户层存在“无”的概念,在实现层可以将“无”也作为一个选择:空。来避免处理“无”的情况。
重要的要暴露出来,不重要的要藏起来。
为了减少复杂度,各模块知晓的信息应越少越好。
但是如果是重要的信息,就应该尽量暴露出来让大家都知道。
有时需要通过异常处理来及早发现问题,这种情况下就不应屏蔽异常。
总结
异常处理代码:特殊情况代码的主要组成部分。
应减少异常处理出现的位置。
异常处理的相关逻辑会极大影响系统复杂度。
网友评论