概述
结论:
如果是
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(数据量越打时,三者方法差别明显)。
- 过滤:如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便可以调用它的remove方法。
- 转换:如果需要遍历列表或数组,并取代它部分或者全部的元素值,就需要列表迭代器ListIterator或者数组索引,以便设定元素的值。(如果直接更改它引用对象的值的话,也可以使用Iterator,前提是符合按引用传递的原则,Iterator的元素为基本数据类型就不会按引用传递,或者它们的包装类,因为是不可变类,也不符合要求。)
- 平行迭代:如果需要并行地遍历多个集合,就需要显式的控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以得到同步前移。
最后
以上就是畅快太阳为你收集整理的List遍历:for,foreach Iterator 速度比较的全部内容,希望文章能够帮你解决List遍历:for,foreach Iterator 速度比较所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复