建议:只针对异常的情况才使用异常。

在现代的JVM实现上,基于异常的模式比标准模式要慢得多。在我的机器上对于一个有100个元素的数组,基于异常的模式比标准满了2倍。

基于异常的循环模式不仅模糊了代码的意图,降低了他的性能,而且他还不能保证正常工作!如果出现了不相关的Bug,这个模式会悄悄地失效,从而掩盖了这个Bug,极大的增加了调试过程的复杂度。假设循环体中的计算过程调用一个方法,这个方法执行了对某个不相关数组的越界访问。如果使用合理的循环模式,这个Bug会产生未被捕捉的异常,从而导致线程立即结束,产生完整的堆栈轨迹。如果使用这个误导的基于异常的循环模式,与这个Bug相关的异常将会被捕捉到,并且被错误的解释为正常的循环终止条件。

这个例子的教训很简单:顾名思义,异常应该只用于异常的情况下,他们永远不应该用于正常的控制流。更一般的,应该优先使用标准的、容易理解的模式,而不是那些声称可以提供更好性能的、弄巧成拙的方法,即使真的能够改进性能,面对平台实现的不断改进,这种模式的性能优势也不可能一直保持。然而,由这种过渡聪明的模式带来的微妙的Bug,以及维护的痛苦却依然存在。

这条原则对于API设计也有启发。设计良好的API不应该强迫他的客户端为了正常的控制流而使用异常。如果类具有“状态相关”的方法,即只有在特定的不可预知的条件下才可以被调用的方法,这个类往往也应该有一个单独的“状态测试”方法,即指示是否可以调用这个状态的方法。例如Iterator接口有一个“状态相关”的next方法和相应的状态测试方法hasNext方法。

另一种提供单独的状态测试方法的做法是,如果“状态相关的”方法被调用时,该对象处于不适当的状态之中,他就会返回一个可识别的值,比如null。这种方法对于Iterator而言并不合适,因为null是next方法的合法返回值。

对于“状态测试方法”和“可识别的返回值”这两种做法,有些指导原则可以帮助你在两者之中做出选择。如果对象将在缺少外部同步的情况下被并发访问,或者可被外界改变状态,使用可被是别的返回值可能是很有必要的,因为在调用“状态测试”方法和调用对应“状态相关”方法的时间间隔之中,对象的状态有可能会发生改变。如果单独的“状态测试”方法必须重复“状态相关”方法的工作,从性能的角度考虑,就应该使用可被识别的返回值。如果所有其他方面都是等同的,那么“状态测试”方法则略优于可被识别的返回值。他提供了更好的可读性,对于使用不当的情形,可能更加易于检测和改正:如果忘了去调用状态测试方法,状态相关的方法就会抛出异常,使这个Bug变得很明显;如果忘了去检查可识别的返回值,这个Bug就很难会被发现。

总而言之,异常是为了在异常情况下使用而设计的。不要将他们用于普通的控制流,也不要编写迫使他们这么做的API。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值