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的组合,理论上这种写法速度更快.