ArrayList容器三种遍历元素方法的性能对比报告
2013-08-14 16:44
791 查看
上周有同事问我ArrayList容器中for循环、ForEach循环和iterator迭代哪种性能更好。其实在此之前我是没有测试过的,所以我想当然地认为,既然iterator方式需要先获取一个iterator,性能应该要差一些。
没有验证过的结论,如鲠在喉。
终于我还是写了下面这个小程序,来验证我的想法。
结果大出我的意料之外。
从上面的测试结果来看,for方式几乎是iterator方式的3倍,而iterator方式几乎是foreach的1.5倍!
秉着探究事实真相的精神,我们来分析下这到底是怎么一回事。
先来看foreach和iterator的差异性。下面是使用javap命令把java的字节码反编译后的Java虚拟机规范定义的字节代码指令,我们来对比下它们的差异性。
ForEach方式:
Iterator方式:
可以看出,foreach循环竟然是用iterator实现的,除了高亮标注的第4、5行外,其它的指令和显式使用iterator方式一模一样。令人不解的是,foreach循环竟然还比显式使用iterator的方式多出了两条指令。看来这就是foreach循环比iterator迭代慢的原因了。jdk5引入的这一新特性除了让代码看起来简洁外,并没有什么高明之处。有点小失望。
再来看看for循环的字节代码指令:
foreach和iterator方式的循环体中有两条invokeinterface的指令;而for循环中只有一条invokeinterface指令,其余的都是堆栈操作,而堆栈操作是快于invokeinterface操作的。这也是for循环快于iterator的原因。
这么看来,要遍历ArrayList中的元素,还是首推for循环,好处有两点:速度快
有的情况下你是需要一个索引号的,而for循环默认就提供了,iterator和foreach还得额外定义变量。
当然,上面的例子中for循环快于iterator是有条件限制的。还是拿上述例子来说,for循环中调用的是list.get方法,而该list是ArrayList,get方法其实就是根据数字下标获取对象。ArrayList的读取是非常快的,就那么几条汇编指令,时间复杂度是o(1)。但是如果把ArrayList换成LinkedList,for循环就会比iterator慢上2 ~ 3个数量级了。原因就在于linkedlist的get方法调用每次都要遍历一遍LinkedList,时间复杂度是o(n)。当然,罪魁祸首是LinkedList.get方法。我贴一个测试结果给你看就明白了。Java
因此,如果要遍历LinkedList容器中的元素,最好还是显式的使用iterator方法。
没有验证过的结论,如鲠在喉。
终于我还是写了下面这个小程序,来验证我的想法。
1234567891011121314151617181920212223242526272829303132333435363738394041424344 | import java.util.ArrayList;import java.util.Iterator;import java.util.LinkedList;import java.util.List; public class ForEachIteratorForPerformanceTest{ public static void main(String[] args) { int loop_count = 100000; String test; List<String> list = new ArrayList<String>(); for (int i = 0; i < loop_count; i++) { list.add(String.valueOf(i)); } long start = System.nanoTime(); for (String s : list) { test = s; } System.out.println(System.nanoTime() - start); start = System.nanoTime(); for (Iterator<String> it = list.iterator(); it.hasNext();) { test = it.next(); } System.out.println(System.nanoTime() - start); start = System.nanoTime(); int size = list.size(); for (int i = 0; i < size; i++) { test = list.get(i); } System.out.println(System.nanoTime() - start); }} |
1 2 3 | 6582505 //ForEach方式遍历大小为十万的ArrayList消耗的时间,单位纳秒,大约6.5毫秒 4596135 //Iterator方式遍历大小为十万的ArrayList消耗的时间,单位纳秒,大约4.5毫秒 1522557 //For方式遍历大小为十万的ArrayList消耗的时间,单位纳秒,大约1.5毫秒 |
秉着探究事实真相的精神,我们来分析下这到底是怎么一回事。
先来看foreach和iterator的差异性。下面是使用javap命令把java的字节码反编译后的Java虚拟机规范定义的字节代码指令,我们来对比下它们的差异性。
ForEach方式:
123456789 | 55: aload 7 57: invokeinterface #41, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 62: checkcast #20; //class java/lang/String 65: astore 6 67: aload 6 69: astore_2 70: aload 7 72: invokeinterface #47, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z 77: ifne 55 |
1 2 3 4 5 6 7 | 108: aload 6 110: invokeinterface #41, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 115: checkcast #20; //class java/lang/String 118: astore_2 119: aload 6 121: invokeinterface #47, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z 126: ifne 108 |
再来看看for循环的字节代码指令:
123456789 | 160: aload_3 161: iload 7 163: invokeinterface #65, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object; 168: checkcast #20; //class java/lang/String 171: astore_2 172: iinc 7, 1 175: iload 7 177: iload 6 179: if_icmplt 160 |
这么看来,要遍历ArrayList中的元素,还是首推for循环,好处有两点:速度快
有的情况下你是需要一个索引号的,而for循环默认就提供了,iterator和foreach还得额外定义变量。
当然,上面的例子中for循环快于iterator是有条件限制的。还是拿上述例子来说,for循环中调用的是list.get方法,而该list是ArrayList,get方法其实就是根据数字下标获取对象。ArrayList的读取是非常快的,就那么几条汇编指令,时间复杂度是o(1)。但是如果把ArrayList换成LinkedList,for循环就会比iterator慢上2 ~ 3个数量级了。原因就在于linkedlist的get方法调用每次都要遍历一遍LinkedList,时间复杂度是o(n)。当然,罪魁祸首是LinkedList.get方法。我贴一个测试结果给你看就明白了。Java
1 2 3 | 2359660 //ForEach方式遍历大小为一万的LinkedList消耗的时间,单位纳秒 284634 //Iterator方式遍历大小为一万的LinkedList消耗的时间,单位纳秒 182291581 //For方式遍历大小为一万的LinkedList消耗的时间,单位纳秒 |
相关文章推荐
- 遍历DataTable内存数据的三种方法性能对比 dataTable.Select优先选择
- 遍历DataTable内存数据的三种方法性能对比
- OpenCV图像元素遍历四种方法的源码及性能对比
- 遍历DataTable内存数据的三种方法性能对比
- 遍历DataTable内存数据的三种方法性能对比 dataTable.Select 用过不?
- 遍历DataTable内存数据的三种方法性能对比 dataTable.Select 用过不?
- 遍历DataTable内存数据的三种方法性能对比 dataTable.Select 用过不?
- 遍历DataTable内存数据的三种方法性能对比
- 遍历DataTable内存数据的三种方法性能对比 dataTable.Select 用过不?
- ArrayList和LinkedList的几种循环遍历方式及性能对比分析(转)
- ArrayList和LinkedList的几种循环遍历方式及性能对比分析
- 技巧:ArrayList删除元素时, 各种方法效率对比
- HashMap三种循环遍历方式及其性能对比
- ArrayList和LinkedList的几种循环遍历方式及性能对比分析
- javascript 三种数组复制方法的性能对比
- java list三种遍历方法性能比較
- 谈谈vector容器的三种遍历方法
- ArrayList边遍历自身边删除元素的方法
- 谈谈vector容器的三种遍历方法
- java list三种遍历方法性能比较