Java迭代器Iterator

之前我们实现了迭代器模式,很多编程语言实际上已经内置了迭代器类,比如Java就为我们实现了迭代器Iterator。我们首先来看Iterator中的源码。

通过JDK源码我们发现Iterator是一个接口,包含三个方法:hasNext、next、remove。

 1 package java.util;
 2
 3 public interface Iterator<E> {
 4
 5     /**
 6     *如果迭代器中还有元素则返回true
 7     */
 8     boolean hasNext();
 9
10     /**
11     *返回迭代器中的下一个元素
12     */
13     E next();
14
15     /**
16     *通过迭代器删除处于集合中最底层的元素
17     */
18     void remove();
19 }

Iterator是一个接口,那如何来创建一个实例呢?要记住,迭代器和集合类的关系非常紧密,我们可以通过集合类来创建一个Iterator实例,ArrayList、LinkedList、Vector都有对它的实现。我们来看ArrayList是如何创建一个Iterator迭代器实例的。在此之前我们先来看看集合和迭代器之间的继承关系。

由于集合的关系相对来说比较复杂,在此我们主要看注释部分,通过阅读源代码会发现ArrayList覆写了AbstractList抽象类中的iterator方法并声称效果更佳,而LinkedList则没有覆写,由此可判断ArrayList的iterator方法比LinkedList中的iterator方法更为高效。

我们直接看ArrayList里中实现的iterator方法。

1 public Iterator<E> iterator() {
2     return new Itr();
3 }    

从代码来看它返回类一个Itr的对象实例,顺着代码看看这个Itr类是什么。

 1 private class Itr implements Iterator<E> {
 2     int cursor;       // 返回下一个元素的索引
 3     int lastRet = -1; // 返回最后一个元素的索引;如果没有则返回-1
 4     int expectedModCount = modCount;
 5
 6     public boolean hasNext() {
 7         return cursor != size;
 8     }
 9
10     @SuppressWarnings("unchecked")
11     public E next() {
12         checkForComodification();
13         int i = cursor;
14         if (i >= size)
15             throw new NoSuchElementException();
16         Object[] elementData = ArrayList.this.elementData;
17         if (i >= elementData.length)
18             throw new ConcurrentModificationException();
19         cursor = i + 1;
20         return (E) elementData[lastRet = i];
21     }
22
23     public void remove() {
24         if (lastRet < 0)
25             throw new IllegalStateException();
26         checkForComodification();
27
28         try {
29             ArrayList.this.remove(lastRet);
30             cursor = lastRet;
31             lastRet = -1;
32             expectedModCount = modCount;
33         } catch (IndexOutOfBoundsException ex) {
34             throw new ConcurrentModificationException();
35         }
36     }
37
38     final void checkForComodification() {
39         if (modCount != expectedModCount)
40             throw new ConcurrentModificationException();
41     }
42 }

原来Itr它是一个私有的内部类,实现Iterator接口。

我们来一行一行读。在第3行中有一个modCount变量。跟踪这个变量,发现这个变量有点意思:

protected transient int modCount = 0;

发现有一个“transient”关键字,查阅资料发现这个关键字的意思是:表示一个域不是该对象序列化的一部分。意思是在对象被序列化时不包括这个变量,至于为什么要这么做呢,我们可以留下一个疑问。(JDk源码注释中是这么说的:The modCount value that the iterator believes that the backing List should have. If this expectation is violated, the iterator has detected concurrent modification.英语太次只能读懂最后一句:如果这个期望是可见性的,那么这个迭代器会检测到有一个并发的修改。猜测是和并发多线程相关。)

hasnext的实现较为简单:

1 public boolean hasNext() {
2     return cursor != size;  //下一个元素的索引是否等于ArrayList的大小
3 }

next的实现:

public E next() {
    checkForComodification();  //检查是否并发修改
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();  //索引大于ArrayList大小抛出异常
    Object[] elementData = ArrayList.this.elementData;  //后面实际是在取ArrayList中的数据
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}

在next方法中我们看到有一个checkForCommodification方法:

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

看来这个modCount变量确实是和并发相关,如果expectedModCount和modCount这两个值不同,则抛出当前正在并发修改的异常。

最后我们来看remove方法的实现:

public void remove() {
    if (lastRet < 0)  //这个地方格外注意,不能在未调用next时直接调用remove方法,必须在remove调用前调用next方法,将通过cursor索引值将其值赋给lastRet
        throw new IllegalStateException();
    checkForComodification();

    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

在remove方法中我们要格外注意,在第一句是检测lastRet是否小于0,我们初始化了lastRet变量-1的值,这意味着,如果我们如果创建完Iterator实例后直接调用remove方法会抛出一个IllegalStateException异常,那怎么才能正确调用呢?那就是在调用remove方法前先调用next方法,此时lastReturn通过cursor索引被赋值,这个时候才能正确使用remove方法。同时它也会调用checkForCommodification方法做并发修改检测。其实我们可以看到JDK源码之所以写到好,是因为它每个方法都做了很多的检测,以确保在尽量多的场景下准确无误地运行。今天关于Java的迭代器就通过JDK源码简单介绍,通过对源码的阅读能够加深我们的理解,这还只是简单的阅读,并没有做很深的理解。最后,我们以为一个Iterator的例子结尾。

 1 package day_29_iterator;
 2
 3 import java.util.ArrayList;
 4 import java.util.Iterator;
 5 import java.util.List;
 6
 7 /**
 8  * @author turbo
 9  *
10  * 2016年9月29日
11  */
12 public class Main {
13
14     /**
15      * @param args
16      */
17     public static void main(String[] args) {
18         List list = new ArrayList();
19         list.add(1);
20         list.add(2);
21         Iterator iterator = list.iterator();
22         while (iterator.hasNext()){
23             System.out.println(iterator.next());
24         }
25     }
26
27 }
时间: 2024-12-15 07:09:31

Java迭代器Iterator的相关文章

设计模式 - 迭代器模式(iterator pattern) Java 迭代器(Iterator) 详解

迭代器模式(iterator pattern) Java 迭代器(Iterator) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考迭代器模式(iterator pattern): http://blog.csdn.net/caroline_wendy/article/details/35254643 Java的标准库(util)中包含迭代器接口(iterator interface), import java.util.Iterator; 继承(

设计模式 - 迭代模式(iterator pattern) Java 迭代器(Iterator) 详细解释

迭代模式(iterator pattern) Java 迭代器(Iterator) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 參考迭代器模式(iterator pattern): http://blog.csdn.net/caroline_wendy/article/details/35254643 Java的标准库(util)中包括迭代器接口(iterator interface), import java.util.Iterator; 继承

java 迭代器Iterator的介绍

 迭代对于我们搞Java的来说绝对不陌生.我们常常使用JDK提供的迭代接口进行Java集合的迭代. [java] view plain copy print? Iterator iterator = list.iterator(); while(iterator.hasNext()){ String string = iterator.next(); //do something } Iterator iterator = list.iterator(); while(iterator.ha

java 迭代器iterator

对于如ArrayList<E>类的数据,常用iterator遍历. ArrayList<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); Iterator<String> iterator = list.iterator(); for(;iterator.hasNext();){

Java 迭代器综述

一.摘要 迭代器模式是与集合共生共死的.一般来说,我们只要实现一个容器,就需要同时提供这个容器的迭代器.使用迭代器的好处是:封装容器的内部实现细节,对于不同的集合,可以提供统一的遍历方式,简化客户端的访问和获取容器内数据.在此基础上,我们可以使用 Iterator 完成对集合的遍历,此外,for 循环和foreach 语法也可以用于遍历集合类.ListIterator 是容器 List容器族特有的双向迭代器.本文要点主要包括: 迭代器模式 Iterator 迭代器 与 Iterable 接口 循

java基础知识5--集合类(Set,List,Map)和迭代器Iterator的使用

写的非常棒的一篇总结: http://blog.csdn.net/speedme/article/details/22398395#t1 下面主要看各个集合如何使用迭代器Iterator获取元素: 1.list使用迭代器Iterator public class testArrayList { public static void main(String args[]) { f1(); f2(); } public static void f1(){ List<String> strList

Java之iterator迭代器和iterable接口

java.lang.Iterable java.util.Iterator Iterator是迭代器类,而Iterable是接口. 好多类都实现了Iterable接口,这样对象就可以调用iterator()方法. 一般都是结合着用,比如 HashMap类就实现了Iterable接口,而要访问或打印出Map中所有内容时,就可以这样: 1 Map hashMap =new HashMap(); 2 Iterator iter = hashMap.iterator(); 3 while(iter.ha

java----数据结构与算法----集合元素的遍历:迭代器--------&gt;JavaAPI:java.util.Iterator+java.util.ListIterator

概述: 迭代器用于集合元素的遍历 迭代器有两种,分别是Iterator和ListIterator Iterator可以用于任何类型集合的遍历 ListIterator只能用于List集合的遍历 ListIterator接口继承了Iterator接口,所以前者拥有后者所定义的所有成员函数,同时,ListIterator还添加了一些具有List集合特性的操作函数,如按照索引访问集合元素.替换/添加集合元素等等 java.util.Iterator /** * @author chen * @date

JAVA之旅(十八)——基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用

JAVA之旅(十八)--基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用 JAVA把完事万物都定义为对象,而我们想使用数据类型也是可以引用的 一.基本数据类型的对象包装类 左为基本数据类型,又为引用数据类型 byte Byte int Integer long Long boolean Booleab float Float double Double char Character 我们拿Integer来举例子 //整