先看两段代码
// 基于异常的模式
String t1[]={"11","22"};
try{
int i=0;
while(true){
System.out.println(t1[i]);
i++;
}
}catch(ArrayIndexOutOfBoundsException e){
}
//标准模式
for(String t:t1){
System.out.println(t);
}
为什么有人优先使用异常模式,而不是标准模式?
他们企图利用java的错误判断机制来提高性能,因为VM对每次数组访问都要检查越界情况,所以正常的终止测试被认为是多余的。这种想法有三个错误:
1.异常机制的设计初衷是用于不正常的情形,所有很少有jvm实现试图对它们进行优化,使得与显示的测试一样快速
2.把代码放在try-catch中反而阻止了现代jvm实现本来可能要执行的特定优化
3.对数组进行变量的标准模式并不会导致冗余的检查。有些现代的jvm实现会将它们优化。
基于异常的模式不仅模糊了代码的意图,降低了它的性能,而且还不能保证正常工作,例如下面的代码:
public static void main(String[] args) {
String t1[]={"11","22"};
try{
int i=0;
while(true){
System.out.println(t1[i]);
test();
i++;
}
}catch(ArrayIndexOutOfBoundsException e){
}
}
private static void test(){
String t2[]={};
t2[0].toString();
}
使用了异常的模式,当产生了与这个bug相关的异常将会被捕捉到,并且被错误的解释为正常的循环终止条件。
设计良好的API不应该强迫它的客户端为了正常的控制流而使用异常,有两种良好的API设计
1.状态测试,指示是否可以调用这个状态相关的方法。例如,
for(Iterator<String> i=collection.iterator();i.hasNext();){
String s=i.next()
}
Iterator接口有一个“状态相关”的next方法,和相应的状态测试方法hasNext().这使得利用传统的for循环对集合进行迭代的标准模式成为可能
2.如果“状态相关的”方法被调用时,该对象处于不适当的状态之中,它就会返回一个可识别的值,比如null。
如果对象将在缺少外部同步的情况下被并发访问,或者可被外界改变状态,使用可被识别的返回值可能是很有必要的。
如果单独的“状态测试”方法必须重复“状态相关”的工作,从性能的角度考虑,就应该使用可被识别的返回值。如果其他方面都是等同的,那么“状态测试”方法则略优于可被识别的返回值。