Java提供了多种数组遍历的方法,从传统的for while到新的foreach. 那么,倒底该选择哪种遍历方式呢,也许很多人不会刻意关心这类问题,人们大多凭个人习惯来选择.
本人以前也不曾注意过,只不过在玩了project euler之后,逐渐开始关心起java程序的性能来(我也不再用C++写了,这种小游戏没必要).
于是乎就做了一个对比试验,在数组中放置从1到1m的数,然后将它们累加起来,计算时间.
为了说明问题,我将分三种方式逐一对比,
1. 使用传统的for循环
2. 使用java的exception
3. 使用foreach
import callback.Callback;
public class Foo {
final static int INIT_NUM = 1000000;
static int array[] = new int[INIT_NUM];
public static void main(String[] args) {
for (int i = 0; i < INIT_NUM; i ++)
array[i] = i + 1;
PerformDiag.perform(new Callback() {
@Override
public void execute() {
testLoop();
}
}, PerformDiag.NANO_PREC);
PerformDiag.perform(new Callback() {
@Override
public void execute() {
testException();
}
}, PerformDiag.NANO_PREC);
PerformDiag.perform(new Callback() {
@Override
public void execute() {
testForeach();
}
}, PerformDiag.NANO_PREC);
}
static void testLoop()
{
int sum = 0;
for (int i = 0; i < array.length; i++)
sum += array[i];
}
static void testException()
{
int sum = 0, i = 0;
while(true)
{
try
{
sum += array[i++];
}
catch (IndexOutOfBoundsException e) { break; }
}
}
static void testForeach()
{
int sum = 0, i = 0;
for (Integer a : array) {
sum += a;
}
}
}
这里PerformDiag是一个简单的性能诊断,只是将回调前后的时间差算出来,精度可以选择milli或nano.
执行结果如下,
use time = 4817412 nano secs
use time = 3322288 nano secs
use time = 20045063 nano secs
可以看到,传统的for循环排在第二位,使用了exception的速度最快,而foreach则远远慢于前两者.
这个结果很容易解释,由于java本身有边界溢出异常,事实上语言框架已经在帮你检查循环条件了,for循环则再一次执行了这个动作,肯定会浪费一些时间.
而如果使用while(true)这样的形式,编译器会优化成一个短跳转指令,这样在代码里就没有条件判断,直到当exception被抛出我们才跳出循环.
而foreach虽然貌似也没有条件判断,但是它只限于wrapper类,频繁的构造对象肯定会对速度产生影响,少打几个字,会付出大量的性能代价.
总的来说,如果你的Java程序对性能比较感冒,建议使用while(true) + exception的组合,理论上这种写法速度更快.