概述
- Effective Java 读书笔记八异常
- 只针对异常情况才使用异常
- 对于可恢复的情况使用受检异常对于编程错误使用运行时异常
- 避免不必要地使用受检异常
- 优先使用标准的异常
- 抛出与抽象相对应的异常
- 每个方法抛出的异常都要有文档
- 在细节消息中包含造成异常的信息
- 努力使失败保持原子性
- 不要忽略异常
Effective Java 读书笔记(八):异常
充分发挥异常的优点,可以提高程序的可读性、可靠性和可维护性。如果使用不当,它们也会带来负面影响。
只针对异常情况才使用异常
异常应该只用于异常的情况下,它们不应该用于正常的控制流。同理,设计良好的 API 不应该强迫客户端为了正常的控制流而使用异常。如果一个类有状态相关的方法,即只有在特定的不可预知的情况下才能调用的方法,这个类也应该有个状态测试的方法,用于指示是否可以调用那个状态相关的方法。比如 Iterator 接口中状态相关的 next 方法和状态测试的 hasNext 方法。
对于可恢复的情况使用受检异常,对于编程错误使用运行时异常
如果期望调用者能够适当地恢复,就应该使用受检异常。通过抛出受检异常,强迫调用者在一个 catch 子句中处理该异常,或者将它传播出去。
通常用运行时异常来表示编程错误,多数运行时异常表示前提违例 precondition violation。
ERROR 通常用于表示资源不足、约束失败,或其他表示程序无法继续执行的情况。
避免不必要地使用受检异常
过分地使用受检异常,会使 API 用起来非常不方便。
优先使用标准的异常
好处是:
1. 使得 API 更加易于学习和使用,因为与程序员已经熟悉的习惯用法一致。
2. 少一个类,省内存。
经常被重用的异常有:
异常 | 含义 |
---|---|
IllegalArgumentException | 参数非法 |
IllegalStateException | 状态错误 |
NullPointerException | 禁止 null 的时候参数为 null |
IndexOutOfBoundsException | 下标参数越界 |
ConcurrentModificationException | 禁止并发修改时,检测到对象的并发修改 |
UnsupportedOperationException | 对象不支持用户请求的方法 |
注意:一定要确保抛出异常的条件,和这些异常的文档描述一致。
抛出与抽象相对应的异常
如果方法抛出的异常与它所执行的任务没有明显的联系,这种情形会让人不知所措。当方法传递由底层抽象抛出的异常时,往往会发生这种情况。除了让人困惑之外,也让实现细节污染了更高层的 API。如果高层实现后续发生了变化,它所抛出的异常也会变化,从而潜在地破坏现有的客户端程序。
为了避免这个问题,更高层的实现应该捕获低层的异常,同时抛出按照高层抽象解释的异常。这种做法称为“异常转译”。
一种特殊的异常转译就是常见的“异常链”,高层异常提供访问方法(Throwable.getCause)来获得低层的异常。
异常不能被滥用,能避免最好,比如调用低层方法之前先做参数检查。
每个方法抛出的异常都要有文档
没有文档,其他人就很难有效地使用你的类和接口。
throws 子句中应该只有受检异常,不能包含非受检异常。但是,文档里应该既有受检异常描述,也有常见的非受检异常描述。
在细节消息中包含造成异常的信息
异常的细节信息应该包含所有“对该异常有贡献”的参数和域的值。
定制异常的时候,可以直接在构造器中输入关键参数信息,并提供访问这些信息的方法。
努力使失败保持原子性
一般而言,失败的方法调用应该使对象保持在被调用之前的状态。具有这种属性的方法被称之为具有“失败原子性”。如何做到失败原子性呢?
1. 使用不可变的对象。
2. 调整计算处理的顺序,让可能失败的部分发生在状态修改之前。
3. 修改状态之前检查参数有效性,比如 Stack 的 pop 方法会在方法开头检查栈大小。
4. 编写异常恢复代码。
如果 API 的方法不具有失败原子性,就应该在 API 文档中指明失败后对象会处于什么样的状态。
不要忽略异常
空的 catch 块会使异常达不到应有的目的。通常会在 catch 块中记录日志和监控,如果真要忽略,也有写一个注释说明为何忽略。
最后
以上就是耍酷小鸭子为你收集整理的Effective Java 读书笔记(八):异常Effective Java 读书笔记(八):异常的全部内容,希望文章能够帮你解决Effective Java 读书笔记(八):异常Effective Java 读书笔记(八):异常所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复