ArrayList与LinkedList遍历方式对比及List遍历技巧

简介: ArrayList与LinkedList遍历方式对比及List遍历技巧

ArrayList遍历方式

首先在主函数中调用ArrayList的构造方法生成一个size为一亿的,element全为aList实例list

int max = 100000000;
List<String> list = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
    list.add("a");
}


接下来看一下常用的五种遍历方法以及所需要的运行时间

for loop

long startTime = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
    list.get(i).hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("for loop: "+(endTime - startTime));

运行结果为:

for loop: 157

for-each loop

long startTime = System.currentTimeMillis();
for (String s : list) {
    s.hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("for-each loop: "+(endTime - startTime));


运行结果为:

for-each loop: 202


Iterator

long startTime = System.currentTimeMillis();
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    iterator.next().hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("Iterator: "+(endTime - startTime));


运行结果为:

Iterator: 177


ListIterator

long startTime = System.currentTimeMillis();
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
    listIterator.next().hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("ListIterator: "+(endTime - startTime));

运行结果为:

ListIterator: 176


java8新特性:forEach

long startTime = System.currentTimeMillis();
list.forEach(t -> t.hashCode());
long endTime = System.currentTimeMillis();
System.out.println("forEach: "+(endTime - startTime));


运行结果为:

forEach: 94


ArrayList遍历方式分析

1.除了java8新特性forEach之外,for loop遍历的方式是最快的,这是因为ArrayList类实现了RandomAccess接口,该接口是一个标志性接口,实现了该接口的类可以支持随机访问,使用for loop遍历的方式快过for-each;

2.Iterator与ListIterator实现类似,只不过ListIterator支持previous方法,可以从后向前遍历;

3.for-each的字节码其实是用Iterator实现的;


LinkedList遍历方式

对于for loop,首先在主函数中调用LinkedList的构造方法生成一个size为十万的,element全为aList实例list

int max = 100000;
List<String> list = new LinkedList<>();
for (int i = 0; i < max; i++) {
    list.add("a");
}

对于其他遍历方式,使用LinkedList的构造方法生成一个size为一亿的,element全为aList实例list

int max = 100000000;
List<String> list = new LinkedList<>();
for (int i = 0; i < max; i++) {
    list.add("a");
}


接下来看一下常用的五种遍历方法以及所需要的运行时间

for loop

long startTime = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
    list.get(i).hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("for loop: "+(endTime - startTime));


运行结果为:

for loop: 3644

为什么仅仅十万个数据,使用for loop遍历一次居然需要3000多ms?因为LinkedList的get(index)方法是从LinkedList的头或尾依次遍历得到的,详见:ArrayList与LinkedList获取指定元素对比;

for-each loop

long startTime = System.currentTimeMillis();
for (String s : list) {
    s.hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("for-each loop: "+(endTime - startTime));

运行结果为:

for-each loop: 401


Iterator

long startTime = System.currentTimeMillis();
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    iterator.next().hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("Iterator: "+(endTime - startTime));


运行结果为:

Iterator: 441


ListIterator

long startTime = System.currentTimeMillis();
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
    listIterator.next().hashCode();
}
long endTime = System.currentTimeMillis();
System.out.println("ListIterator: "+(endTime - startTime));


运行结果为:

ListIterator: 452

java8新特性:forEach

long startTime = System.currentTimeMillis();
list.forEach(t -> t.hashCode());
long endTime = System.currentTimeMillis();
System.out.println("forEach: "+(endTime - startTime));

运行结果为:

forEach: 435

LinkedList遍历方式分析

  1. for-each loop遍历的方式是最快的,这是因为LinkedList类没有实现RandomAccess接口,不支持随机访问,使用for-each loop遍历的方式快过for loop


List遍历技巧


有时候我们仅仅只会得到一个List实例,但我们并不能够知道它的底层实现是ArrayList还是LinkedList或者是其他的类,这是我们如何以最快的速度遍历它呢?

可以判断该实例是否实现了RandomAccess接口,如果实现了该接口,说明支持随机访问,使用for-loop进行遍历最快;否则使for-each loop进行遍历最快。

示例代码如下:

if (list instanceof RandomAccess) {
    /**
     * for loop
     */
    long startTime1 = System.currentTimeMillis();
    for (int i = 0; i < list.size(); i++) {
        list.get(i).hashCode();
    }
    long endTime1 = System.currentTimeMillis();
    System.out.println("随机访问: "+(endTime1 - startTime1));
} else {
    /**
     * for-each loop
     */
    long startTime2 = System.currentTimeMillis();
    for (String s : list) {
        s.hashCode();
    }
    long endTime2 = System.currentTimeMillis();
    System.out.println("顺序访问: "+(endTime2 - startTime2));
}
目录
相关文章
|
12天前
|
索引 容器
06-python数据容器-list列表定义/list的10个常用操作/列表的遍历/使用列表取出偶数
06-python数据容器-list列表定义/list的10个常用操作/列表的遍历/使用列表取出偶数
|
3月前
使用Lamda表达式、stream流遍历Map、list
使用Lamda表达式、stream流遍历Map、list
|
9月前
|
存储 Java 开发者
Java-数据结构(三)-List:ArrayList和LinkedList及其相关面试题
Java-数据结构(三)-List:ArrayList和LinkedList及其相关面试题
143 0
|
5月前
|
容器
List特点和遍历方式及增长因子论证和去重原理和LinkedList特点
List特点和遍历方式及增长因子论证和去重原理和LinkedList特点
27 0
|
6月前
|
存储 安全 Java
一.list集合的特点与linkedlist特性的论证
一.list集合的特点与linkedlist特性的论证
33 0
|
6月前
|
XML 存储 JSON
java框架集合List子接口之ArrayList源码剖析
ArrayList使用尾删法时 , 时间复杂度为O(1) , 并且会把最后一个元素置位null , 其它删除时间复杂度为O(N) , 因为会涉及到元素的移动以及元素的遍历 ArrsyList是线程不安全的
26 0
|
6月前
|
存储 Java 索引
java集合框架List子接口之LinkedList源码剖析
LinkendList从物理结构来说是一种线性结构 , 而从逻辑结构来说是一种链式存储结构 , 虽然是线性结构 , 但是并不会按照线性的顺序存储 , 而是分散存储在内存中 , 通过指针来建立节点与节点之间的联系, 同时实现了Deque这也说明它是一个双向链表 , 在源码中 , 没有看到它对线程安全问题的处理 , 所以它同时还是一个线程不安全的链表 , 也没有看到不允许插入null元素 , 重复元素的处理 , 所以它又是一个允许重复元素以及null元素的链表
34 0
|
8月前
|
Java
面试时常常考察的java遍历List、Set、Map方法
面试时常常考察的java遍历List、Set、Map方法
|
8月前
|
存储 Java
Java中 List集合接口及其主要的实现类ArrayList,Vector,LinkedList的详解
Java中 List集合接口及其主要的实现类ArrayList,Vector,LinkedList的详解
40 0
|
8月前
|
安全
List和ArrayList的区别
List和ArrayList的区别
45 0