经常使用ArrayList遍历,尝试总结一下for配合get()的遍历和Iterator配合next()遍历的区别,进入Java的JDK源码中进行深度剖析一下
这里参考一下http://bbs.youkuaiyun.com/topics/250025827论坛的测试程序:
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
/**
* IteratorTest
*
* @author SageZk
*/
public class IteratorTest {
public static long testForloops(List<String> list) {
long start = 0L;
long end = 0L;
start = System.nanoTime();
for (int i = list.size() - 1; i >= 0; --i) {
list.get(i);
}
end = System.nanoTime();
return end - start;
}
public static long testIterator(List<String> list) {
long start = 0L, end = 0L;
start = System.nanoTime();
Iterator<String> it = list.iterator();
while (it.hasNext()) {
it.next();
}
end = System.nanoTime();
return end - start;
}
public static void main(String[] args) {
// 测试列表长度
final int LEN = 10000;
// 初始化测试用数据
List<String> arraylist = new ArrayList<String>();
List<String> linkedlist = new LinkedList<String>();
for (int i = 0; i < LEN; ++i) {
String s = Integer.toString(i, 2);
arraylist.add(s);
linkedlist.add(s);
}
// 打印测试结果
final String FORMAT = "%1$-16s%2$-16s%3$16d\n";
System.out.println("List\t\tType\t\tTime(nanoseconds)");
System.out.println("-------------------------------------------------");
System.out.printf(FORMAT, "ArrayList", "for", testForloops(arraylist));
System.out.printf(FORMAT, "ArrayList", "Iterator",
testIterator(arraylist));
System.out
.printf(FORMAT, "LinkedList", "for", testForloops(linkedlist));
System.out.printf(FORMAT, "LinkedList", "Iterator",
testIterator(linkedlist));
}
}
运行程序:
ListTypeTime(nanoseconds)
-------------------------------------------------
ArrayList for 607064
ArrayList Iterator 809922
LinkedList for 154326455
LinkedList Iterator 958140
可以看到使用LinkedList链表式的列表遍历的话差距就很明显。
使用ArrayList列表的话,使用for比较快一些。
根据这里的区别,我跟踪了一下源码。
ArrayList的Iterator和for-get两种遍历
next
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
get
private transient Object[] elementData;
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
可以看出两种方法使用的都是从Object[]数组中直接返回return (E) elementData[index]的形式读取节点,所以就区别而言,是 for遍历的get的读取速度稍微快一点但是不会很明显,因为next()还需要进行一次指向赋值操作和基本类型的赋值。
LinkedList的Iterator和for-get两种遍历
next
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
private Node<E> next;
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
get
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
可以看出LinkedList的next是直接链式节点一个一个读取,这里的 链式节点的next读取速度就可以和for循环的get读取速度拉开一个比较乐观的明显的距离了。
总结一下
短评一下,如果是链式列表的话使用next(),如果只是一般的ArrayList进行遍历,使用for和get组合就可以了。for和get的配合,代码简单符合一般程序员的习惯,而且效率高,所以以后碰到ArrayList的遍历就不要在纠结下去了。本文来自优快云博客,转载请联系作者注明出处http://blog.youkuaiyun.com/dreamintheworld