To Java程序员:切勿用普通for循环遍历LinkedList

ArrayList与LinkedList的普通for循环遍历

对于大部分Java程序员朋友们来说,可能平时使用得最多的List就是ArrayList,对于ArrayList的遍历,一般用如下写法:

public static void main(String[] args) { List<Integer> arrayList = new ArrayList<Integer>(); for (int i = 0; i < 100; i++) arrayList.add(i); for (int i = 0; i < 100; i++) System.out.println(arrayList.get(i)); }

如果以后要用到LinkedList了,可能有些朋友就会用一样的方式去遍历LinkedList了:

public static void main(String[] args) { List<Integer> linkedList = new LinkedList<Integer>(); for (int i = 0; i < 100; i++) linkedList.add(i); for (int i = 0; i < 100; i++) System.out.println(linkedList.get(i)); }

请记住:这是一种非常糟糕的做法。这其实已经不是Java的问题,而是数据结构的问题了,我相信语言从Java换成其他的也都一样。

下面对ArrayList和LinkedList的普通for循环效率进行测试以及分析原因。

ArrayList和LinkedList使用普通for循环遍历速度对比

先给出测试代码:

public class ListIteratorTest { private final static int LIST_SIZE = 1000; public static void main(String[] args) { List<Integer> arrayList = new ArrayList<Integer>(); List<Integer> linkedList = new LinkedList<Integer>(); for (int i = 0; i < LIST_SIZE; i++) { arrayList.add(i); linkedList.add(i); } long startTime = System.currentTimeMillis(); for (int i = 0; i < arrayList.size(); i++) arrayList.get(i); System.out.println("ArrayList遍历速度:" + (System.currentTimeMillis() - startTime) + "ms"); startTime = System.currentTimeMillis(); for (int i = 0; i < linkedList.size(); i++) linkedList.get(i); System.out.println("LinkedList遍历速度:" + (System.currentTimeMillis() - startTime) + "ms"); } }

不断增大LIST_SIZE,我用表格表示一下运行结果:

    1000   5000   10000   50000   100000  
ArrayList   0ms   1ms   2ms   3ms   3ms  
LinkedList   3ms   16ms   88ms   2446ms   18848ms  

从运行结果我们看到,按倍数增大List容量,ArrayList的遍历显得比较稳定,而LinkedList的遍历几乎是爆发式的增长,再测试下去已经没有必要了。

下面解释一下产生此现象的原因。

ArrayList使用普通for循环遍历快的原因

先看一下ArrayList的get方法源代码:

public E get(int index) { RangeCheck(index); return (E) elementData[index]; }

看到ArrayList的get方法只是从数组里面拿一个位置上的元素罢了。我们有结论,ArrayList的get方法的时间复杂度是O(1),O(1)的意思也就是说时间复杂度是一个常数,和数组的大小并没有关系,只要给定数组的位置,直接就能定位到数据。

其实熟悉C、C++或者对指针理解的朋友一定很好理解为什么,我解释一下为什么对数组使用get就快。

在计算机底层,数据都是有地址的,就像人有住址一样。假设我写了这么一句代码:

int[3] ints = {1, 3, 5};

在Java中一个int型数据是4个字节,此时计算机内部做的事情是,在内存空间中找到一块连续的、足以存放3个4字节也就是12字节的数组的内存空间,并返回该内存空间的首地址。比方说该内存空间的首地址是0x00吧,那么那么1就放在0x00~0x03中、3就放在0x04~0x07中、5就放在0x08~0x0B中。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/5080e9edf870917eea7821489bebf7e6.html