《第8章 异常》
异常是Java语言中非常重要、而又容易被轻视的、一个出于非常奇妙的地位的一个东东。这一章讲了关于有效使用异常的指导性原则。
【第39条】只针对不正常的条件才使用异常
异常只应该被用于不正常的情况,它们永远不应该被用于正常的控制流。书中举了一个特殊的例子,在这个例子中,循环的结束条件是当数组下标出界时引发的一个 ArrayIndexOutOfBoundsException。这段程序的作者“自作聪明”地认为“传统”的 for 循环 或 while 循环 需要在每次进行大小判断,是要额外耗费时间的,所以“发明”了这种每次执行完循环体不必“浪费时间去比较大小”的写法,直到产生“下标越界”异常后结束循环。
而事实上,JVM会对那些“传统”的 for while 循环做各种各样的性能优化,而绝不会去对 try-catch 块做出什么优化。这样的“自作聪明”其实反而降低了性能。同时,这样的“非常规”写法,也是代码的可读性急剧下降。而且这种依靠通过异常来达到程序流控制目的的代码,很容易与bug等异常混淆在一起,给调试工作带来了很大的麻烦。
这一条原则,同样也对API的设计者有所启示。当我们在写一个具有状态相关的方法时,不应该强迫调用者为了正常的控制流而使用异常。具有状态相关的方法,简单的说就是不是在什么情况下都可以使用,只有特点条件下才可以。例如,只有在数据库已连接的状态下,才可以调用的数据库操作方法 等。
进一步解释一下,就是说,我们应该通过一个状态检查方法来控制流,而不是使用异常:
// 应该这样
if db.isConnected() {
result = db.select(sql);
}
// 而不该这样
try{
result = db.select(sql);
}catch (DatabaseNotConnectException e){
.....
}
如果称这种方式为“状态检测法”,那么还有一种方式可以称之为“可被识别的返回值”方式。比如,在上面的例子中,既不使用 if 也不适用 try-catch,在 select 方法中,当数据库尚未连接时,不是抛出一个DatabaseNotConnectException,而是返回 null 。
那么正两种方式该如何选择呢?首先,当null是正常情况下本身就可能的一个返回值时“可被识别的返回值”就不适用了,例如书中Iterator.next()的例子。其次,在多线程的程序中,检查状态和真正调用之间,状态可能会被其他线程改变,这种时候就可以使用“可被识别的返回值”方式。最后,当不存在状态检测不稳定的前提下,可以忽略状态检测本身的性能耗费而选用“状态检测法”。
总结:这一条中的前一半,讲的不可用异常来控制程序流,估计我们应该不会犯这样的错误,就当是“无则加免”吧。后一半,讲的两种“方式”倒是非常值得学习和借鉴的。
【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208
分享到:
相关推荐
这个概念在第39章中被提到,主要讨论如何通过调试技巧来识别和应对这种技术。在加壳过程中,为了防止原始可执行文件(PE)的入口点(OEP,Original Entry Point)被轻易找到,一些壳程序会将OEP的原始指令挪移至壳...
[第39节] 1.4.6 多态的使用:父类作为返回值3 [第40节] 1.5.1 汽车租赁运行效果2 [第41节] 1.5.2 汽车租赁框架1 [第42节] 1.5.2 汽车足联框架2 [第43节] 1.5.3 处理空指针异常1 [第44节] 1.5.3 处理空指针异常2 [第...
该压缩包文件“中国银行外汇牌价爬虫----查询指定日期九点三十分以后第一条汇率。.zip”包含了实现特定功能的代码资源,主要是用于自动抓取中国银行在指定日期9:30之后的首个外汇汇率数据。这个爬虫程序可能是Python...
- 使用`break filename:lineno if condition`可以设置条件断点,只有当满足条件时才会触发断点。 8. **忽略断点** - 使用`ignore breakpointnum count`命令可以让gdb在到达断点时忽略一定次数,这对于排除重复...
#### 十九、查看栈信息 - **查看调用栈**:使用 `backtrace`(bt)命令查看当前的调用栈信息。 - **查看特定帧**:使用 `frame` 命令查看调用栈中的特定帧信息。 #### 二十、信号 - **查看信号**:使用 `info ...
第三条详细规定了新安装、大修或改造后的起重机以及在用起重机的检验周期和要求。 第四条提到,规程的技术指标和要求参考了《起重机械安全规程》(GB6067-1985)、《起重机设计规范》(GB/T3811-1983)等相关国家标准,...
27.2.5 什么时候不使用parallel类 568 27.2.6 从任务返回值 571 27.3 任务和ui线程一起使用 574 27.4 取消任务和处理异常 578 27.4.1 协作式取消的原理 578 27.4.2 使用aggregateexception类处理任务异常 586 ...
第三十,switch不能直接作用于byte,long,但可以通过类型转换。从Java 7开始,switch可以作用于String。 第三十一,Singleton模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。实现方式有多种,如...
第三十一,switch不能作用于byte上,但Java 7以后可以作用于char、byte、short、int以及枚举类型;不能作用于long,但可以作用于String(Java 7以后)。 第三十二,Singleton模式是一种设计模式,确保一个类只有一...
第三题考察对磁场基本概念的理解,磁场的方向不由小磁针决定,而是由磁场本身的性质决定,所以C选项错误。第四题通过丝绸摩擦玻璃棒产生的静电现象,结合电荷间的相互作用,得出甲带正电,乙可能带负电或不带电的...
结果打印出来的数据正常,不可能为零,仔细查看相关代码,问题只可能在指针移位上有问题,果然在函数中发现一处比较隐蔽的错误。 /* 功能:一个BM模块内所有小区CDB侧广播消息忙闲情况 */ /***************************...
第三题询问面向对象的三大特性,即封装、继承和多态。第四题涉及到数据结构的选择,ArrayList、LinkedList和Vector的性能比较,其中LinkedList在中间插入和删除效率较高。第五题是一个字符串相关的题目,测试了对象...
- **第三节 有限售条件的股份上市流通**:针对有限售条件的股份提出了特别规定,如锁定期限制等。 #### 第六章 定期报告 - **主要内容**:本章详细规定了上市公司年度报告、中期报告及其他定期报告的编制与披露...
第二十至第三十二的问题涉及Java语言的多个方面,包括类的继承、多线程、异常处理、语法特性、数据类型以及设计模式等。这些问题的回答需要详细解释各个概念并给出示例代码,篇幅较长,无法在此处一一展开。在实际...
这意味着即使操作员具有权限,但由于服务本身未被激活,仍然无法正常使用相关功能。 #### 三、历史交易查询错误 **问题**: 在测试中发现,当客户未签约相应服务时,做历史交易(b2e0035)查询时,返回的错误为何是...
同步使用synchronized关键字修饰同步方法,而stop()和suspend()方法由于可能导致线程安全问题,因此不推荐使用。 47. sleep()和wait()的区别? sleep()是Thread类的方法,调用后线程暂时让出CPU执行权,但不会释放...
第十七讲至第十九讲:异常处理 讲解了C++的异常处理机制,如何抛出和捕获异常,以及在编写健壮程序时异常处理的重要性。 第二十讲:文件操作 介绍了输入/输出流的概念,如何使用fstream库进行文件读写操作,以及...
#### 第三章 转向柱上的控制装置 - **照明/转弯信号控制杆**:说明控制杆如何控制前照灯、雾灯、转向信号灯等。 - **挡风玻璃雨刮器和洗涤器杆**:解释如何操作雨刮器和喷水装置。 - **后车窗雨刮器/洗涤器开关**:...
1. **制定依据**:本办法根据公司的人事管理规则第三十九条制定,表明这是公司内部人力资源管理的一部分。 2. **适用对象**:适用于公司正式编制内的从业人员,而不包括聘约、定期契约或临时人员。 3. **申请退休...