Effective Java 第三版——73.抛出合乎于抽象的异常
Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。

73. 抛出合乎于抽象的异常
当一个方法抛出一个与它所执行的任务没有明显关联的异常时,这是令人不安的。在方法传播由低层(lower-level)抽象抛出的异常时,会经常发生这种情况。它不仅令人不安,而且用实现细节“污染”了上层的API。如果上层(higher layer)的实现在以后的版本中发生变化,那么它抛出的异常也会发生变化,可能会破坏现有的客户端程序。
为了避免这个问题,上层(higher layers)应该捕获低层( lower-level )的异常,并在它们的位置抛出可以用上层级别(higher-level )抽象来解释的异常。这个习语被称为异常转译:
// Exception Translation
try {
... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException e) {
throw new HigherLevelException(...);
}
以下的异常转转译的示例是来自AbstractSequentialList类,该类是List接口的骨架实现(skeletal implementation )(条目 20)。 在此示例中,异常转译由List <E>接口中的get方法规范强制要求的:
/**
* Returns the element at the specified position in this list.
* @throws IndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()}).
*/
public E get(int index) {
ListIterator<E> i = listIterator(index);
try {
return i.next();
} catch (NoSuchElementException e) {
throw new IndexOutOfBoundsException("Index: " + index);
}
}
如果较低级别的异常可能有助于调试导致较高级别异常的问题,则需要一种称为异常链(exception chaining )的特殊异常转译形式。低层异常(原因)传递给高层异常,高层异常提供一个访问器方法(Throwable的getCause方法)来检索低层异常:
// Exception Chaining
try {
... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException cause) {
throw new HigherLevelException(cause);
}
高级异常的构造方法将原因传递给一个感知链(chaining-aware)的父类构造方法,因此它最终被传递给Throwable的一个感知链的构造方法,比如Throwable(Throwable):
// Exception with chaining-aware constructor
class HigherLevelException extends Exception {
HigherLevelException(Throwable cause) {
super(cause);
}
}
大多数标准异常都有感知链的构造方法。对于没有这样做的异常,可以使用Throwable的initCause方法设置原因。异常链接不仅允许你以编程方式访问原因(使用getCause),而且还将原因的堆栈跟踪集成到更高级别异常的堆栈跟踪中。
虽然异常转译优于低层异常的无意识传播,但不应过度使用。 在可能的情况下,处理较低层异常的最佳方法是通过确保较低级别的方法成功执行来避免异常。 有时可以通过检查更高级别方法的参数的有效性,然后再将它们传递到较低层来完成此操作。
如果不可能防止来自较低层的异常,那么接下来最好的事情就是让较高层静默地解决这些异常,从而使较高级别方法的调用者与较低级别的问题隔离开来。 在这些情况下,使用某些适当的日志记录工具(如java.util.logging)记录异常可能是适当的。 这允许程序员调查问题,同时把使用者和客户端代码隔离开。
总之,如果无法阻止或处理较低层的异常,那么使用异常转译,除非较低级别的方法恰好保证其所有异常都适用于较高级别。 异常链接提供了两全其美的优势:它允许抛出适当的更高级别异常,同时可以捕获失败分析的根本原因(条目 75)。
Effective Java 第三版——73.抛出合乎于抽象的异常的更多相关文章
- Effective Java 第三版——70. 对可恢复条件使用检查异常,对编程错误使用运行时异常
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- Effective Java 第三版——74. 文档化每个方法抛出的所有异常
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Effective Java 第三版——39. 注解优于命名模式
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——13. 谨慎地重写 clone 方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——72. 赞成使用标准异常
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Effective Java 第三版——57. 最小化局部变量的作用域
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Effective Java 第三版——49. 检查参数有效性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- Codeforces 1131F Asya And Kittens (构造)【并查集】
<题目链接> 题目大意:有$n$只小猫,开始将它们放在指定的n个单元格内,然后随机从n-1个隔板中拆除隔板,最终使得这些小猫在同一单元格.现在依次给出拆除隔板的顺序,比如:1 4 就表示1 ...
- 37_Reverse3_digit_Integer
描述 反转一个只有3位数的整数. 你可以假设输入一定是一个只有三位数的整数,这个整数大于等于100,小于1000. [ ] 您在真实的面试中是否遇到过这个题? 样例 123 反转之后是 321. 90 ...
- UVA 221 Urban Elevations
思路: 一些解释: ①:建筑的排序: 下面是以输入顺序为标号,在数组bd中的顺序: 排序后在数组bd中的顺序: 以后我们比较就按这个顺序 ②:x坐标的排序 x的内容是每一个建筑的左边界和右边界,我们把 ...
- Redis自学笔记:2.准备
第2章:准备 '纸上得来终觉浅,绝知此事要躬行'--陆游 2.2启动和停止redis 表2-1 redis可执行文件说明 文件名 说明 redis- server redis服务器 redis-cli ...
- innerHTML innerText与outerHTML间的区别
innerHTML与innerText及outerHTML间的区别最容易使初学者搞混淆,为了更好的使读者区分开.下面我就通过一个demo来解释: 代码: <!DOCTYPE html>&l ...
- stdio.h cstdio的区别
stdio.h cstdio string.h cstring math.h cmath .h是c语言的习惯,在c++中,替换为在前面加个c
- Oracle中 (+)与left join 的用法区别
Oracle中 (+)与left join 的用法区别 原创 2017年01月11日 13:33:42 6648 select * from a,b where a.id=b.id(+); (+)写在 ...
- poj3009 Curling 2.0(很好的题 DFS)
https://vjudge.net/problem/POJ-3009 做完这道题,感觉自己对dfs的理解应该又深刻了. 1.一般来说最小步数都用bfs求,但是这题因为状态记录很麻烦,所以可以用dfs ...
- ISAPI多进程设置
ISAPI多进程设置 IIS默认配置下采用的是单工作进程的工作模式,也就是只启用一个w3wp.exe进程处理所有请求,然后进程内启用多个线程来处理并发请求,最大工作线程数由具体的操作系统和IIS来决定 ...
- mui 从列表进入到详情,再返回,列表页还是进入列表之前的样子,而不刷新页面
mui 从列表进入到详情,再返回,列表页还是进入列表之前的样子,而不刷新页面