ArrayList
代码如下:
package com.danhar.mbox.fegin;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author wu
* @version 1.0
* @date 2020/12/29/029
*/
public class ListTest {
public static void main(String[] args) {
long d1, d2;
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
list.add(i);
}
System.out.println("List first visit method:");
d1 = System.currentTimeMillis();
for (Integer integer : list) {
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
System.out.println("List second visit method:");
d1 = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
System.out.println("List Third visit method:");
d1 = System.currentTimeMillis();
int a = list.size();
for(int i = 0; i<a; i++){
Object o = list.get(i);
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
System.out.println("List fourthly visit method:");
d1 = System.currentTimeMillis();
Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
iter.next();
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
}
}
运行结果为:
List first visit method:
Run Time:15(ms)
List second visit method:
Run Time:9(ms)
List Third visit method:
Run Time:9(ms)
List fourthly visit method:
Run Time:12(ms)
对ArrayList测试
直接用循环的方法,get(index)来获取对象,是最快的方式。
For Each的效率最差,用迭代器的效率也没有很好。但只是相对而言,其实从时间上看最多也就差几毫秒。
然而,这并不是事实的全部真相!!!
上面的测试,我们只是用了ArrayList来做为List的实现类。所以才有上面的结论。
For each其实也是用了迭代器来实现,只不过这个Iterator是Java编译器帮我们生成的,所以我们不需要再手动去编写。但是因为每次都要做类型转换检查,所以花费的时间比Iterator略长。时间复杂度和Iterator一样,也因为用了迭代器,所以速度上受了影响。不如直接get(index)快。
那为何get(index)会比较快呢?
因为ArrayList是通过动态数组来实现的,支持随机访问,所以get(index)是很快的。迭代器,其实也是通过数组名+下标来获取,而且增加了逻辑,自然会比get(index)慢。
LinkedList
package com.danhar.mbox.fegin;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* @author wu
* @version 1.0
* @date 2020/12/29/029
*/
public class ListTest {
public static void main(String[] args) {
long d1, d2;
List<Integer> list = new LinkedList<>();
for (int i = 0; i < 1000000; i++) {
list.add(i);
}
System.out.println("List first visit method:");
d1 = System.currentTimeMillis();
for (Integer integer : list) {
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
System.out.println("List second visit method:");
d1 = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
System.out.println("List Third visit method:");
d1 = System.currentTimeMillis();
int a = list.size();
for (int i = 0; i < a; i++) {
Object o = list.get(i);
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
System.out.println("List fourthly visit method:");
d1 = System.currentTimeMillis();
Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
iter.next();
}
d2 = System.currentTimeMillis();
System.out.println("Run Time:" + (d2 - d1) + "(ms)");
System.out.println();
}
}
跟ArrayList完全不一样了。最突出的就是get(index)的方式,随着size的增加,急剧上升。到10万数据量时,光遍历时间都要三四秒,这是很可怕的。那为何会有这样的结果呢?还是和LinkedList的实现方式有关。LinkedList是通过双向链表实现的,无法支持随机访问。当你要向一个链表取第index个元素时,它需要二分后从某一端开始找,一个一个地数才能找到该元素。这样一想,就能明白为何get(index)如此费时了。
总结
(1)对于ArrayList和size<1000的LinkedList来说,每种遍历方式差异不大;
(2)对于size较大的LinkedList,建议使用迭代器或者foreach的方式进行遍历,否则效率将会有明显的差距。
综合来看,使用foreach方法比较合适。
另外,除去效率的考虑,也应该在设计上花心思,实际上把大量的对象放入list内本身就是需要考虑的问题