推荐:体系化学习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就使用迭代器遍历。