源码剖析Iterator接口遍历和直接for-get组合遍历的区别

经常使用ArrayList遍历,尝试总结一下for配合get()的遍历和Iterator配合next()遍历的区别,进入Java的JDK源码中进行深度剖析一下

这里参考一下http://bbs.csdn.net/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的遍历就不要在纠结下去了。

本文来自CSDN博客,转载请联系作者注明出处http://blog.csdn.net/dreamintheworld

时间: 2024-08-28 12:48:50

源码剖析Iterator接口遍历和直接for-get组合遍历的区别的相关文章

【Java集合源码剖析】HashMap源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap. HashMap 实现了Serializable接口,因此它支持序列化,

HashMap(2) 源码剖析(推荐)

今天看代码,想到去年发生的HashMap发生的CPU使用率100%的事件,转载下当时看的三个比较不错的博客(非常推荐) 参考:http://coolshell.cn/articles/9606.html   http://github.thinkingbar.com/hashmap-analysis/ http://developer.51cto.com/art/201102/246431.htm 在 Java 集合类中,使用最多的容器类恐怕就是 HashMap 和 ArrayList 了,所以

STL&quot;源码&quot;剖析-重点知识总结

STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合套用: 容器(Containers):各种数据结构,如:vector.list.deque.set.map.用来存放数据.从实现的角度来看,STL容器是一种class template. 算法(algorithms):各种常用算法,如:sort.search.copy.erase.从实现的角度来看,STL算法

【源码】LinkedList源码剖析

//----------------------------------------------------------- 转载请注明出处:http://blog.csdn.net/chdjj by Rowandjj 2014/8/8 //---------------------------------------------------------- 注:以下源码基于jdk1.7.0_11 上一篇我们分析了ArrayList,今天我们再来看下LinkedList. 首先上一幅框架图: Lin

【源码】ArrayList源码剖析

//-------------------------------------------------------------------- 转载请注明出处:http://blog.csdn.net/chdjj by Rowandjj 2014/8/7 //-------------------------------------------------------------------- 从这篇文章开始,我将对java集合框架中的一些比较重要且常用的类进行分析.这篇文章主要介绍的是Array

转:【Java集合源码剖析】HashMap源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票,谢谢! 投票地址:http://vote.blog.csdn.net/Article/Details?articleid=35568011 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动

转:【Java集合源码剖析】Hashtable源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/36191279 Hashtable简介 Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中. Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆.

Apache Flink fault tolerance源码剖析(一)

因某些童鞋的建议,从这篇文章开始结合源码谈谈Flink Fault Tolerance相关的话题.上篇官方介绍的翻译是理解这个话题的前提,所以如果你想更深入得了解Flink Fault Tolerance的机制,推荐先读一下前篇文章理解它的实现原理.当然原理归原理,原理体现在代码实现里并不是想象中的那么直观.这里的源码剖析也是我学习以及理解的过程. 作为源码解析Flink Fault Tolerance的首篇文章,我们先暂且不谈太有深度的东西,先来了解一下:Flink哪里涉及到检查点/快照机制来

STL源码剖析 --- 空间配置器 std::alloc

STL是建立在泛化之上的.数组泛化为容器,参数化了所包含的对象的类型.函数泛化为算法,参数化了所用的迭代器的类型.指针泛化为迭代器,参数化了所指向的对象的类型.STL中的六大组件:容器.算法.迭代器.配置器.适配器.仿函数. 这六大组件中在容器中分为序列式容器和关联容器两类,正好作为STL源码剖析这本书的内容.迭代器是容器和算法之间的胶合剂,从实现的角度来看,迭代器是一种将operator*.operator->.operator++.operator-等指针相关操作予以重载的class tem