什么是迭代器模式?

我们知道,Java中对于集合的遍历提供了一种很简单的实现——Iterator类。
一般我们对集合遍历时,都会做如下程序:

List<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);

Iterator<Integer> iterator = arrayList.iterator();
while(iterator.hasNext()) {
	System.out.println(iterator.next());
}

这又被称为对集合的迭代,而Iterator就是对应的迭代器

所以,迭代器模式是什么?顾名思义,就是提供了一种方法顺序访问一个聚合对象中的各个元素,却又不暴露该对象的内部表示。

举个例子:
我们去医院都要先排号,这时所有排号的人就构成了一个列表,医生负责的就是从头开始,一个一个将人叫进来,当前谁正在进行诊治,下一个要诊治的人是谁,这个人是否是最后一个人,他不需要去考虑这些人是做什么的,他需要做的仅仅是遍历这些人,这就是迭代器模式。

也就是说,Java中的集合实现了这个迭代器后,他本身的所有状态就由迭代器自己来维护了,客户端进行调用的时候不需要知道集合内部如何进行的遍历操作,而仅仅需要发出指令:遍历下一个,是否结束,就可以对不同集合进行遍历。

迭代器模式的具体实现

主要以Java中集合的迭代为例。
首先Java维护了一个迭代器的根类型Iterator

package java.util;
public interface Iterator<E> {
    boolean hasNext();

    E next();

    void remove();
}

而所有的集合类的根类型Iterable中声明了一个方法以用来返回迭代器对象:

package java.lang;

import java.util.Iterator;
public interface Iterable<T> {
    Iterator<T> iterator();
}

这样,在集合类中只要维护其自身的iterator()方法,就可以实现对不同集合类型的迭代。
ArrayList类举例,看其重写的iterator()方法:

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

可以看到,其返回了一个Itr对象,而Itr正是ArrayList内部维护的一个类

private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            // 实现代码
        }

        @SuppressWarnings("unchecked")
        public E next() {
            // 实现代码
        }

        public void remove() {
           // 实现代码
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            // 实现代码
        }

        final void checkForComodification() {
            // 实现代码
        }
    }

具体源码不深入解读了,这就是迭代器模式具体的实现框架方式。

注意点

在迭代时需要注意的是不能对底层集合的元素进行动态的删改,可以使用Iterator中的remove()方法对最后一个迭代器返回的元素进行删除,比如:

List<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);

Iterator<Integer> iterator = arrayList.iterator();
iterator.next();
arrayList.add(4);
iterator.next();

这样是不行的,会抛出ConcurrentModificationException异常。
ArrayList来举例,在ArrayList中维护了一个版本号,而在Iterator的实现中对版本号进行了判断(就是上面的最后一个方法):

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

modCount是当前集合的版本号,而expectedModCount是当前迭代器的版本号,在每次迭代器实例化时会初始化为modCount(也就是执行iterator()时),而更新集合时迭代器的版本号不会更新,此时就会抛出异常。

至于Java为什么要这样做,是因为集合的快速失败机制(fail-fast),这里主要是说设计模式的思想,所以不再深入。