第5章 异常(Exceptions)
19 只在异常的情况下使用异常(Use exceptions only for exceptional conditions)
异常只应该使用在异常情况下,而决不应该用作通常的控制流。
一个设计良好的API不应该强制其客户使用异常来用作通常的控制流。一个包含了只能在特定状态下调用的方法的类通常有一个状态检测的方法来判断是否适合调用上述方法。例如Iterator类的next和hasNext方法。
另外一种做法是让依赖于状态的方法在不正确的状态下被调用时返回一个不同寻常的值,比如null。
20 对于可恢复的情况使用检查的异常,对于程序错误使用运行时异常(Use checked exceptions for recoverable conditions and run-time exceptions for programming errors)
在可以预期调用者能够恢复的时候使用检查的异常。
使用运行时异常来表明程序错误。
所有的未检查的异常都应该继承RuntimeException。
如果不能确定是否能恢复,就最好使用未检查的异常。
检查的异常的类最好提供一些附加的相关信息来帮助调用者恢复。
21 避免不必要的使用检查的异常(Avoid unnecessary use of checked exceptions)
不同于返回值,异常强制程序员去处理异常情况,极大的增强了可靠性。
使用异常的负担是程序员需要编写额外的try和catch语句。
22 使用标准的异常(Favor the use of standard exceptions)
23 根据抽象级别抛出合适的异常(Throw exceptions appropriate to the abstraction)
高层应该捕获低层的异常,并抛出在高层抽象可以理解的异常。
24 文档化每个方法抛出的所有异常(Document all exceptions thrown by each method)
总是单独声明检查的异常,并使用Javadoc的@throws来记录每个异常抛出的条件。
使用Javadoc的@throws来记录每个方法可以抛出的未检查异常,但是不要使用throws在方法的定义中包括未检查的异常。
25 在详细信息中包含失败-捕获的信息(Include failure-capture information in detail messages)
为了捕获失败,异常的字符串表示应该包含造成该异常的所有的参数的域的值。
异常的表示字符串不同于用户级别的错误信息。
26 尽量保持失败的原子性(Strive for failure atomicity)
一次失败的方法调用应该使得对象的状态和调用之前一致。
如果对象是不可变的,那么本身就具有失败原子性。
如果对象是可变的,可以有如下四种方法来解决:
1) 在执行操作之前检查参数的合法性。
2) 对计算进行排序,使得有可能失败的部分首先执行。
3) 编写一定的恢复代码,当失败发生时,使得对象的状态回滚到操作执行之前。通常用在持久化存储的数据结构上。
4) 在对象的一个临时副本上执行操作,所有操作执行完之后,再修改原始对象的状态。
27 不要忽略异常(Don’t ignore exceptions)
一个空的catch语句块违背了异常的目的。
至少一个 catch 语句块应该包含注释,说明为什么可以忽略该异常。