异常处理需要考虑的三个问题
处理程序异常,需要解决以下3个问题:
Where:哪个地方发生了异常?Who: 谁来处理异常?How: 如何处理异常?
平时自己在写代码的时候,经常会纠结,我这个代码发生了异常,这个异常是需要向外抛出给调用者,还是要自己处理?《码出高效》给出这样一个基本原则:
如果异常在当前方法的处理能力范围之内且没有必要对外透出,那么就直接捕获异常并做相应的处理;否则就向上抛出,由上层方法或者框架来处理。
以FileNotFound为例子。读取一个文件,如果文件不存在,这个异常是需要对外抛出还是自己处理呢?其他方法跟该方法交互的时候,一般会期待该方法:1. 根据文件内容进行一些设置(例如设置环境变量,实例化一些config等)2. 返回内容。当文件读取这个阶段出错的时候,我们是需要及时对调用方返回状态信息的。如果什么都不做,可能就会导致调用方误认为被调用方工作正常,从而导致调用方后续依赖调用方本次工作结果的工作发生异常。此时,及时反馈就很重要了。所以个人认为,在读文件这个操作对一些环境设置负责的时候,如果发生异常,需要向上抛出。具体需要依赖场景。以下是我认为的一些典型场景:
- 读取文件内容负责对外返回一定的处理信息。调用方和被调用方之间如果具有一定的契约(例如,约定返回
Null就是出现异常),那么此时调用方可以对异常进行处理而不对外抛出。如果没有明确的约定,那么最佳实践就是抛出异常,在语法层面要求被调用方对异常进行处理。
关于空指针异常
书中提到了2种编程理念:1. 契约式编程 2. 防御式编程
推荐拥抱防御式编程的理念(感觉跟我司的“人性本恶”有一拼^_^),即不信任任何一方的输入和输出。当然这是相对的,否则又会陷入无限判空的地狱中。