foreach list java_java遍历List的三种方式比较 用数据说明为什么推荐使用foreach

参考链接:http://www.trinea.cn/android/arraylist-linkedlist-loop-performance/https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.14.2

foreach也称为增强for循环,是java5新特性,可用于遍历数组或实现了Iterable接口的集合容器。

1.遍历List的方式:

假设已有数据:

List list;

(1) foreach循环:

for (Integer j : list) {

// use j

}

(2) 下标递增(递减)循环:

int size = list.size();

for (int j = 0; j < size; j++) {

list.get(j);

}

(3) 迭代器循环迭代:

for (Iterator iterator = list.iterator(); iterator.hasNext();) {

iterator.next();

}

2.三种遍历方式的性能比对

经测试通过上述三种方式分别迭代ArrayList和LinkedList时所消耗的时间如下:

compare loop performance of ArrayList

-----------------------------------------------------------------------

list size | 10,000 | 100,000 | 1,000,000 | 10,000,000

-----------------------------------------------------------------------

for each | 1 ms | 3 ms | 14 ms | 152 ms

-----------------------------------------------------------------------

for iterator | 0 ms | 1 ms | 12 ms | 114 ms

-----------------------------------------------------------------------

for size = list.size() | 0 ms | 0 ms | 6 ms | 62 ms

-----------------------------------------------------------------------

compare loop performance of LinkedList

-----------------------------------------------------------------------

list size | 100 | 1,000 | 10,000 | 100,000

-----------------------------------------------------------------------

for each | 0 ms | 1 ms | 1 ms | 2 ms

-----------------------------------------------------------------------

for iterator | 0 ms | 0 ms | 0 ms | 2 ms

-----------------------------------------------------------------------

for size = list.size() | 0 ms | 0 ms | 67 ms | 8216 ms

3.List遍历方式及其性能表现分析:

ArrayList:

当size < 100万时,三种方式性能差别不大;

当size >= 100万时,for > iterator >= foreach.

LinkedList:

当size小于1万时,三种方式性能差别不大;

当size>=1万时, iterator >= foreach > for.

由于foreach底层也是通过iterator来迭代,因此foreach的性能与iterator接近。

是什么影响了这三种遍历方式的性能呢?

主要原因是List的底层数据结构和从List容器中获取元素的算法。

我们知道ArrayList的底层数据结构是数组,LinkedList是链表。

这三种遍历方式从List中获取元素的算法分别为:

1) foreach循环和iterator迭代器:

都是调用iterator.next(),查看ArrayList对于iterator中next方法的实现可知其最终是通过数组下标获取元素。如下图:

d6808655a05cd62142b90e251a615143.png

ArrayList迭代之next

查看LinkedList对于iterator中next方法的实现可知其最终是调用了父类AbstractList中iterator的实现,然后调用了get(index),而LinkedList的get方法是通过遍历链表来获取元素的。如下图:

ec496fe4f0fa31dcf2a52843e40dfc4e.png

2) for循环:调用get(index).

综上,这三种遍历方式从容器中获取元素的方式如下图:

可见遍历ArrayList时最终都是直接通过数组下标定位元素的,这应该是当ArrayList的容量在100万以内时,其遍历时间在20ms以内的根本原因。

遍历LinkedList时最终都是查询链表。但为什么iterator方式遍历LinkedList的速度是for的数千倍呢?因为iterator利用了游标,而后者是调用了get(index)方法将链表从头到尾或从尾到头查了一遍。

4.为什么推荐使用foreach

最后我们来看一下为什么诸如《Effective-Java》都推荐使用foreach:

1) 性能较优:

分析上文性能测试结果发现,通过foreach遍历ArrayList时当size < 100万时,时间在20ms以内,并不比for循环差多少。遍历size在百万以上的超大ArrayList的时其性能明显低于for循环遍历方式。

通过foreach遍历LinkedList时,无论size大小,其性能始终接近于最优的iterator遍历方式。

2) 书写简洁。

3) 不必关心元素下标,可避免数组下标越界。

最后别忘了点波关注哦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值