关于for循环和Iterator遍历ArrayList的性能问题

今日看到@DriveMan的一篇博客,题为《ArrayList集合实现RandomAccess接口有何作用?为何LinkedList集合却没实现这接口?》,文中提到对于实现了RandomAccess接口的类来说,使用for循环遍历比使用Iterator遍历更加高效快速。

由于本人之前没了解过这方面的知识,阅此博客后心怀好奇便去查阅了API文档了解了一下,官网的介绍是这样的:

Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.

 上面这段话的意思就是:RandomAccess是一个标记接口,用于标明实现了该接口的List支持快速随机访问。并且指出了该接口的主要用途是当随机或顺序访问一些List时,允许泛型算法改变它们的行为来提升性能。

此外,官方还列举了一个例子,提到使用for循环遍历的速度会比Iterator遍历的速度要快。原文如下:

     for (int i=0, n=list.size(); i < n; i++)
         list.get(i);

runs faster than this loop:
     
     for (Iterator i=list.iterator(); i.hasNext(); )
         i.next();

在@DriveMan的文中,测试了for与Iterator遍历ArrayList的性能,结论与官网描述一致,for循环稍快与Iterator。


怀着一颗好奇心,本人也想试试看是否真的如此,于是也开始了测试。话不多说,直接上代码和结果:

public class ArrayListDemo {
    public static void main(String[] args) {
        //存储一些数据到集合中
        List arrayList = new ArrayList<>();
        for (int i = 0; i < 50000; i++) {
            arrayList.add(i);
        }
        System.out.println("for遍历ArrayList:" + arrayListFor(arrayList));
        System.out.println("Iterator遍历ArrayList:" + arrayListIterator(arrayList));
    }
    //使用for循环遍历ArrayList
    public static long arrayListFor(List arrayList) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < arrayList.size(); i++) {
            arrayList.get(i);
        }
        long end = System.currentTimeMillis();
        return end - start;
    }
    //使用Iterator遍历ArrayList
    public static long arrayListIterator(List arrayList) {
        long start = System.currentTimeMillis();
        for (Iterator i = arrayList.iterator(); i.hasNext();) {
            i.next();
        }
        long end = System.currentTimeMillis();
        return end - start;
    }
}

首先我准备了50000条数据进行测试,这与@DriveMan文中是一致的,这样方便对比。运行5次后,结果如下:

50000条数据时的测试结果
遍历方式 第1次运行 第2次运行 第3次运行 第4次运行 第5次运行
for 5 ms 3 ms 4 ms 5 ms 4 ms
Iterator 5 ms 4 ms 5 ms 5 ms 3 ms

由以上结果可以看到,50000条数据时,for循环略占优一些(但第5次运行是Iterator占优)。


由于数据量过少,for优势好像不是很明显,于是我将数据量改为50000000,再次测试for与Iterator的性能并进行对比,测试结果如下:

50000000条数据时的测试结果
遍历方式 第1次运行 第2次运行 第3次运行 第4次运行 第5次运行
for 52 ms 47 ms 56 ms 50 ms 45 ms
Iterator 15 ms 12 ms 11 ms 15 ms 11 ms

奇怪的现象出现了!50000000条数据时,for遍历耗费的时间基本都是Iterator的4倍左右!for循环遍历完全落入下风!

反复测试之,依旧如此,这似乎与官网API文档中的描述矛盾了。

至此,原因未知,如有知情者,欢迎在下方评论解释一下,指导指导大家。

如本文中有错误,恳请指出,感激不尽。

欢迎大家加入自学Java的QQ群25011579,里面全都是自学Java的小伙伴,大家一起努力吧!

你可能感兴趣的:(Java,SE)