推荐:体系化学习Java(Java面试专题)

我的开发宗旨:
开发的代码一定要短,不是任何情况下都能用设计模式的。

正题:为什么?

我们先看RandomAccess源码上的一段介绍:

/**
 * Marker interface used by <tt>List</tt> 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.
 *
 * <p>The best algorithms for manipulating random access lists (such as
 * <tt>ArrayList</tt>) can produce quadratic behavior when applied to
 * sequential access lists (such as <tt>LinkedList</tt>).  Generic list
 * algorithms are encouraged to check whether the given list is an
 * <tt>instanceof</tt> this interface before applying an algorithm that would
 * provide poor performance if it were applied to a sequential access list,
 * and to alter their behavior if necessary to guarantee acceptable
 * performance.
 *
 * <p>It is recognized that the distinction between random and sequential
 * access is often fuzzy.  For example, some <tt>List</tt> implementations
 * provide asymptotically linear access times if they get huge, but constant
 * access times in practice.  Such a <tt>List</tt> implementation
 * should generally implement this interface.  As a rule of thumb, a
 * <tt>List</tt> implementation should implement this interface if,
 * for typical instances of the class, this loop:
 * <pre>
 *     for (int i=0, n=list.size(); i < n; i++)
 *         list.get(i);
 * </pre>
 * runs faster than this loop:
 * <pre>
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * </pre>
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @since 1.4
 */
 public interface RandomAccess {
}

我来对上面的注释做一个简短的解释:
大致意思:该接口的主要目的是在随机访问或顺序访问列表时提供较好的性能,也就是说这个接口只是一个标记类,实现该接口的类在随机访问或顺序访问列表时性能较高。
“ runs faster than this loop”, 说的是for (int i=0, n=list.size();i++) 比 for (Iterator i=list.iterator(); i.hasNext())运行效率比下面的高。

我们写个简单的代码坐下测试吧!

package com.example.demo.demo_0331_collection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class WhyAchieveRandomAccess {

    /**
     *
     *  我们本次是要了解为什么 ArrayList要实现RandomAccess接口?
     *  而LinkedList为什么不实现RandomAccess?
     */
    public static void main(String[] args) {
        List<Integer> testArrayList = initTestArrayList();
        List<Integer> testLinkedList = initTestLinkedList();
        long arrayListForeachTime = getArrayListForeachTime(testArrayList);
        long arrayListIteratorTime = getArrayListIteratorTime(testArrayList);
        long linkedListForeachTime = getLinkedListForeachTime(testLinkedList);
        long linkedListIteratorTime = getLinkedListIteratorTime(testLinkedList);
        System.out.println("ArrayList Foreach 时间:" + arrayListForeachTime);
        System.out.println("ArrayList Iterator 时间:" + arrayListIteratorTime);
        System.out.println("LinkedList Foreach 时间:" + linkedListForeachTime);
        System.out.println("LinkedList Iterator 时间:" + linkedListIteratorTime);
    }

    public static List<Integer> initTestArrayList() {
        List<Integer> testList = new ArrayList<>();
        for(int i = 0; i <= 1000000; i++) {
            testList.add(i);
        }
        return testList;
    }

    public static List<Integer> initTestLinkedList() {
        List<Integer> testList = new LinkedList<>();
        for(int i = 0; i <= 10000; i++) {
            testList.add(i);
        }
        return testList;
    }

    public static long getArrayListForeachTime(List<Integer> testArrayList) {
        long start = System.currentTimeMillis();
        for(int i = 0; i < testArrayList.size(); i++) {
            testArrayList.get(i);
        }
        long end = System.currentTimeMillis();
        return (end - start);
    }

    public static long getArrayListIteratorTime(List<Integer> testArrayList) {
        long start = System.currentTimeMillis();
        Iterator<Integer> iterator = testArrayList.iterator();
        while (iterator.hasNext()) {
            iterator.next();
        }
        long end = System.currentTimeMillis();
        return (end - start);
    }

    public static long getLinkedListForeachTime(List<Integer> testLinkedList) {
        long start = System.currentTimeMillis();
        for(int i = 0; i < testLinkedList.size(); i++) {
            testLinkedList.get(i);
        }
        long end = System.currentTimeMillis();
        return (end - start);
    }

    public static long getLinkedListIteratorTime(List<Integer> testLinkedList) {
        long start = System.currentTimeMillis();
        Iterator<Integer> iterator = testLinkedList.iterator();
        while (iterator.hasNext()) {
            iterator.next();
        }
        long end = System.currentTimeMillis();
        return (end - start);
    }

}
// 输出结果
ArrayList Foreach 时间:10
ArrayList Iterator 时间:12
LinkedList Foreach 时间:99
LinkedList Iterator 时间:2

总结

1、ArrayList 实现RandomAccess接口,是表示顺序遍历的效率要高于Iterator遍历的效率
2、LinkedList 未实现RandomAccess接口,顺序遍历的效率明显低于Iterator遍历的效率
3、我测试了下遍历100000个数据时,ArrayList 顺序遍历的效率要和Iterator遍历的效率差不多,也就是数据越小,他们的性能基本没区别。但是数据1000000时,差距就很明显了。而 LinkedList 几千就开始有差距了。
4、大家可以查看Collections 中的 indexedBinarySearch 方法和 iteratorBinarySearch 方法,学习下实现了RandomAccess接口的List就使用索引遍历,而未实现RandomAccess接口的List就使用迭代器遍历。