zoukankan      html  css  js  c++  java
  • 关于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<Integer> 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<Integer> 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<Integer> 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文档中的描述矛盾了。

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

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

  • 相关阅读:
    (转)Linux系统调用和库函数调用的区别
    一个“梦想实践重度障碍者”的思考
    按字节输出数据
    内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理]
    VimdiffVIM的比较和合并工具
    [每天进步一点 流水账]回顾总结
    计算机就业方向
    ofstream和ifstream详细用法(转)
    ECMAScript 运算符关系运算符
    ECMAScript 语句标签语句
  • 原文地址:https://www.cnblogs.com/muhy/p/10593405.html
Copyright © 2011-2022 走看看