Effective Java 第三版——71. 避免不必要地使用检查异常
Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。

71. 避免不必要地使用检查异常
许多Java程序员不喜欢检查异常,但如果使用得当,他们可以改进API和程序。 与返回码和未检查异常不同,它们迫使程序员处理异常问题,增强可靠性。 也就是说,在API中过度使用检查异常会使它们使用起来不那么令人愉快。 如果方法抛出检查异常,则调用它的代码必须在一个或多个catch块中处理它们,或者声明抛出它们并向上传播。 无论哪种方式,它都会给API的使用者带来负担。这种负担在Java 8中加重了,因为抛出检查异常的方法不能直接在Stream中使用(条目45——48)。
如果不能通过正确使用API来防止异常情况,并且使用API的程序员在遇到异常时可以采取一些有用的操作,那么这种负担是合理的。除非满足这两个条件,否则可以使用未检查异常。作为最后的检验(litmus test),可以问问自己:程序员将如何处理异常。这是最好的办法吗?
} catch (TheCheckedException e) {
throw new AssertionError(); // Can't happen!
}
或者这样:
} catch (TheCheckedException e) {
e.printStackTrace(); // Oh well, we lose.
System.exit(1);
}
如果程序员不能做得更好,则需要一个未检查异常。
如果方法抛出的检查异常是惟一的,那么检查异常给程序员带来的额外负担就会大得多。如果还有其他方法,则该方法必须已经出现在try块中,并且最多需要另一个catch块。如果一个方法抛出单个检查异常,那么这个异常就是该方法必须出现在try块中,并且不能直接在Stream中使用。在这种情况下,有必要问问自己是否有办法避免检查异常。
消除检查异的最简单方法是返回所需结果类型的Optional(条目 55)。该方法只返回一个空的Optional,而不是抛出一个检查的异常。这种方法的缺点是,该方法不能返回任何详细说明其无法执行所需计算的额外信息。相反,异常具有描述性类型,并且可以导出方法来提供额外的信息(条目 70)。
还可以通过将抛出异常的方法分解为两个方法,将检查异常转换为未检查异常,第一个方法返回一个boolean值,表示是否抛出异常。 这个API重构将调用序列:
// Invocation with checked exception
try {
obj.action(args);
} catch (TheCheckedException e) {
... // Handle exceptional condition
}
转换为:
// Invocation with state-testing method and unchecked exception
if (obj.actionPermitted(args)) {
obj.action(args);
} else {
... // Handle exceptional condition
}
这种重构并不总是合适的,但是它可以使API更加舒适。 虽然后者调用序列并不比前者更漂亮,但重构的API更灵活。 如果程序员知道调用将成功,或者满足于让线程在失败时终止,那么重构也允许这个简单的调用序列:
obj.action(args);
如果怀疑普通的调用序列会成为常态,那么API重构可能是合适的。生成的API本质上与条目 69中的状态测试方法API,并且适用与相同的警告:如果要在没有外部同步的情况下同时访问对象,或者被外部转换状态,则此重构是不合适的,因为对象的状态可能是在对actionPermitted和action的调用之间进行更改。如果单独的actionPermitted方法会重复action方法的工作,则可能会因性能原因而排除重构。
总之,如果谨慎使用,检查异常可以提高程序的可靠性;当过度使用,会使API难以使用。如果调用者无法从失败中恢复,则抛出未检查异常。如果恢复是可能的,并且希望强制调用者处理异常条件,那么首先考虑返回Optional的。只有当在失败的情况下,无法提供充分的信息时,才应该抛出一个检查的异常。
Effective Java 第三版——71. 避免不必要地使用检查异常的更多相关文章
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——7. 消除过期的对象引用
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——10. 重写equals方法时遵守通用约定
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——14.考虑实现Comparable接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——18. 组合优于继承
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——21. 为后代设计接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——32.合理地结合泛型和可变参数
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- SPOJ RPLN (模板题)(ST算法)【RMQ】
<题目链接> 题目大意:给你一段序列,进行q次区间查询,每次都输出询问区间内的最小值. 解题分析: RMQ模板题,下面用在线算法——ST算法求解.不懂ST算法的可以看这篇博客 >& ...
- 图片预览组件PhotoView
图片预览组件PhotoView PhotoView是一款图片预览组件,广泛应用于大图的查看.该组件支持图片手势缩放.旋转等功能.它可以很好的和ViewPager.Picasso等组件结合,实现各种复杂 ...
- 深入理解arguments.callee
在函数内部,有两个特殊的对象:arguments 和 this.其中, arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 a ...
- java菜鸟之微信分享
前言:我终于理解了什么叫做教科书:教科书就是把一些简单容易的知识写成一堆谁都看不懂的书,这,就简称“教科书” 这些天接触到微信分享以及回调的问题,因为之前没接触过,所以这次做这个分享,碰了一点点壁,特 ...
- word表分页表头
选中表,右键-表格属性. 调出表格属性对话框. 选择行,在各页顶端以标题行形式重复出现划上钩确定.
- BZOJ.2000.[HNOI2010]stone取石头游戏(博弈)
BZOJ 洛谷 低估这道神题了_(:з」∠)_ MilkyWay好狠啊(小声) \(Description\) 有一些数字,被分成若干双端队列(从两边都可以取)和最多两个栈(只能从某一边一个一个取)的 ...
- 基于asp.net的excel导入导出
新建aspx文件.代码大概如下: <!--导入Excel文件--> <table width="99%" border="0" align=& ...
- js form表单 鼠标移入弹出提示功能
JS 部分 /* Copyright (C) 2009 - 2012 Email: wangking717@qq.com WebSite: Http://wangking717.javaeye.com ...
- RbbitMQ 的 python 实现方法
RbbitMQ(消息队列) #简单模式 服务端 import pika #连接 connection = pika.BlockingConnection(pika.ConnectionParamete ...
- python系统编程(四)
进程池Pool 当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到mu ...