目录
1.什么是Iterator模式
直接翻译的话其实是叫做迭代器模式,在英文单词中有重复做某件事情的意思。迭代器的作用就是把for循序遍历集合的这个过程抽象出来,实现在数据集合中遍历数据的功能
2.为什么需要Iterator模式
其实我们知道迭代器模式其实就是for循环,那么它跟for循环有什么区别值得我们去使用这个模式呢?我认为最重要的原因就是它可以将遍历和实现完全区分开来。我们知道我们一般使用Iterator模式实现循环遍历的话,是用以下代码实现的。
当我们使用map的时候可以这样子实现循环
Map<String,String> map=new HashMap<>();
map.put("11","1");
map.put("22","2");
Iterator<String> mapIterator= map.keySet().iterator();
while (mapIterator.hasNext()){
String ss=mapIterator.next();
System.out.println(ss);
}
map的Iterator的具体实现类的具体方法
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
当我们使用list的时候可以这样子实现循环
List<String> list=new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Iterator<String> stringIterator=list.iterator();
while (stringIterator.hasNext()){
String ss=stringIterator.next();
System.out.println(ss);
}
list的Iterator实现类的具体实现方法
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
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];
}
通过上述两个小例子我们可以发现,无论我们的集合是用的什么数据结构存储数据的,我们都可以通过iterator模式来循环遍历所有数据,并且用来遍历的代码无需改变。我们实现遍历的类是Iterator的实现类,这与集合类完全剥离了开来,我们无需关心集合类的数据结构,我们只需要关心我们的迭代器即可。而迭代器的实现是集合类实现的,我们无需关心它如何实现,开箱即用就可以了。这样子不管我们是什么样的集合我们都可以用一样的方法去遍历集合
3.Iterator模式的主要角色
- Iterator(迭代器接口)
此接口定义了遍历的方法,主要是包括了hasNext和next的方法。hasNext()方法返回的是一个boolean类型的值,这个值在返回最后一个元素之前会返回true,当返回了最后一个元素之后就会返回fasle。而next()方法则会返回一个当前下标的值,之后再将下标往后移动一位。
在这里我们查看java的util包中帮我们实现的Iterator接口类,发现了不仅有hasnext和next,还添加了remove和forEachRemaining默认方法。forEachRemaining是方便我们直接遍历集合的所有数据的简便操作
public interface Iterator<E> {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
E next();
/**
* Removes from the underlying collection the last element returned
* by this iterator (optional operation). This method can be called
* only once per call to {@link #next}. The behavior of an iterator
* is unspecified if the underlying collection is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @implSpec
* The default implementation throws an instance of
* {@link UnsupportedOperationException} and performs no other action.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this iterator
*
* @throws IllegalStateException if the {@code next} method has not
* yet been called, or the {@code remove} method has already
* been called after the last call to the {@code next}
* method
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(next());
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
mapIterator.forEachRemaining(System.out::println);
- ConcreteIterator(迭代器具体实现)
负责实现Iterator接口,在这里我们以ArrayList动态数组来查看Iterator的实现类
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() {
return cursor != size;
}
@SuppressWarnings("unchecked")
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];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
再看看其他的Iterator实现类,例如map的keyIterator的实现类
final class KeyIterator extends HashIterator implements Iterator<K> {
public final K next() { return nextNode().key; }
}
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
- Aggregate(集合接口)
该角色负责定义创建Iterator角色的接口,我们来看看java的具体实现是如何的。
我们可以知道java中的Collection接口就是我们的Aggregate集合接口
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
...省略
}
- ConcreteAggregate(集合具体实现)
从刚刚的Collection接口的注释来看,有以下接口类是实现了此接口的
* @see Set
* @see List
* @see Map
* @see SortedSet
* @see SortedMap
* @see HashSet
* @see TreeSet
* @see ArrayList
* @see LinkedList
* @see Vector
* @see Collections
* @see Arrays
* @see AbstractCollection
我们来看看实现了List接口的abstratList类,发现已经实现了Iterator的接口方法
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public Iterator<E> iterator() {
return new Itr();
}
...省略
}
4.总结
使用迭代器模式,可以帮助我们将遍历和实现分离开来。如上面所示在众多迭代器的实现中,我们都可以用同一的方法去遍历,而无需关心迭代器的实现细节,这也是接口的好处,而迭代器的实现又是集合类去完成的,我们很好地将集合的遍历和集合的实现分离开来。
参考书籍 :《图解设计模式》
作者:【日】结城浩
翻译:杨文轩