List遍历:for,foreach Iterator 速度比较

结论:
如果是 ArrayList ,用三种方式遍历的速度是for>Iterator>foreach,速度级别基本一致; 
如果是 LinkedList ,则三种方式遍历的差距很大了,数据量大时越明显(一般是超过100000级别),用for遍历的效率远远落后于foreach和Iterator,Iterator>foreach>>>for; 

模拟100000条数据,放入ArrayList和LinkedList,对两个List分别用三种方式进行遍历,耗时如下图所示: 

public class Test {

	public static void main(String[] args) {
		// 初始化
		List<String> arrList = new ArrayList<String>();
		List<String> linkList = new LinkedList<String>();
		for (int i = 0; i < 100000; i++) {
			arrList.add( String.valueOf( i ) );
			linkList.add( String.valueOf( i ) );
		}
		System.out.println( "---------------------测试结果------------------------" );
		System.out.println( "for  arrList 时间是 \t" + testFor( arrList ) );
		System.out.println( "iterator arrList 时间是 \t" + testIterator( arrList ) );
		System.out.println( "Foreach  arrList 时间是 \t" + testForeach( arrList ) );
		System.out.println( "---------------------------------------------------" );
		System.out.println( "for linkList 时间是 \t" + testFor( linkList ) );
		System.out.println( "iterator linkList 时间是 \t" + testIterator( linkList ) );
		System.out.println( "Foreach  linkList 时间是 \t" + testForeach( linkList ) );
	}

	public static long testFor(List<String> list) {
		long startTime = 0L, endTime = 0L;
		String str;
		startTime = System.nanoTime();
		for (int i = list.size() - 1; i >= 0; i--) {
			str = list.get( i );
		}
		endTime = System.nanoTime();
		return endTime - startTime;
	}

	public static long testIterator(List<String> list) {
		long startTime = 0L, endTime = 0L;
		String str;
		startTime = System.nanoTime();
		Iterator<String> it = list.iterator();
		while (it.hasNext()) {
			str = it.next();
		}
		endTime = System.nanoTime();
		return endTime - startTime;

	}
	
	public static long testForeach(List<String> list) {
		long startTime = 0L, endTime = 0L;
		String str;
		startTime = System.nanoTime();
		for (String string : list) {
			str=string;
		}
		endTime = System.nanoTime();
		return endTime - startTime;

	}

探索原因: 
1:测试发现foreach和Iterator基本上都在一个速度级别,但Iterator会稍稍快于foreach,事实上,foreach就是基于Iterator实现的,可通过反编译工具看到。下面两段代码效果是一样的:

// foreach
for(Object obj : list){  
    System.out.println(obj);  
}

// Iterator
Iterator<Object> iterator = list.iterator();  
while(iterator.hasNext()){  
    Object obj = iterator.next();  
    System.out.println(obj);  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

所以foreach和Iterator基本是效率相当的,慢的时间猜测就是foreach隐式转换成Iterator所消耗的时间.

2:接下来要解释的是为什么ArrayList的遍历中for比Iterator快,而LinkedList中却是Iterator远快于for?这得从ArrayList和LinkedList两者的数据结构说起了: 
ArrayList是基于索引(index)的数组,索引在数组中搜索和读取数据的时间复杂度是O(1),但是要增加和删除数据却是开销很大的,因为这需要重排数组中的所有数据。 
LinkedList的底层实现则是一个双向循环带头节点的链表,因此LinkedList中插入或删除的时间复杂度仅为O(1),但是获取数据的
时间复杂度却是O(n)。 
明白了两种List的区别之后,就知道,ArrayList用for循环随机读取的速度是很快的,因为ArrayList的下标是明确的,读取一个数据的时间复杂度仅为O(1)。但LinkedList若是用for来遍历效率很低,读取一个数据的时间复杂度就达到了为O(n)。而用Iterator的next()则是顺着链表节点顺序读取数据的效率就很高了。

最后总结: 
1:ArrayList用三种遍历方式都差得不算太多,一般都会用for或者foreach,因为Iterator写法相对复杂一些。
2:LinkedList的话,推荐使用foreach或者Iterator(数据量越打时,三者方法差别明显)。 

Effective Java中建议,一般情况下使用foreach进行循环,因为其在简洁性和预防Bug方面有着传统for循环无法比拟的优势,并且没有性能损失。但是除了一下三种情况: 
  • 过滤:如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便可以调用它的remove方法。
  • 转换:如果需要遍历列表或数组,并取代它部分或者全部的元素值,就需要列表迭代器ListIterator或者数组索引,以便设定元素的值。(如果直接更改它引用对象的值的话,也可以使用Iterator,前提是符合按引用传递的原则,Iterator的元素为基本数据类型就不会按引用传递,或者它们的包装类,因为是不可变类,也不符合要求。)
  • 平行迭代:如果需要并行地遍历多个集合,就需要显式的控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以得到同步前移。
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值