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

首先增强for循环和iterator遍历的效果是一样的,也就说增强for循环的内部也就是调用iteratoer实现的,但是增强for循环有些缺点,例如不能在增强循环里动态的删除集合内容。不能获取下标等。

结论:

如果是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);  
}  

所以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(数据量越大时,三者方法差别明显)。

建议,一般情况下使用foreach进行循环,因为其在简洁性和预防Bug方面有着传统for循环无法比拟的优势,并且没有性能损失。但是除了一下三种情况:

  • 过滤:如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便可以调用它的remove方法。
  • 转换:如果需要遍历列表或数组,并取代它部分或者全部的元素值,就需要列表迭代器ListIterator或者数组索引,以便设定元素的值。(如果直接更改它引用对象的值的话,也可以使用Iterator,前提是符合按引用传递的原则,Iterator的元素为基本数据类型就不会按引用传递,或者它们的包装类,因为是不可变类,也不符合要求。)
  • 平行迭代:如果需要并行地遍历多个集合,就需要显式的控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以得到同步前移。

你可能感兴趣的:(后端)