首先预览下Java源码中的Iterator和Iterable:
Iterable接口:
1 public interface Iterable{ //这里只摘录接口中的抽象方法2 /**3 * Returns an iterator over elements of type { @code T}.4 *5 * @return an Iterator.6 */7 Iterator iterator();8 9 }
Iterator接口:
public interface Iterator{ /** * 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();}
用Iterator模式实现遍历集合
Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。
例如,如果没有使用Iterator,遍历一个数组的方法是使用索引: for(int i=0; i<array.size(); i++) { ... get(i) ... }
而访问一个链表(LinkedList)又必须使用while循环: while((e=e.next())!=null) { ... e.data() ... }
以上两种方法客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。
更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。
解决以上问题,Iterator模式总是用同一种逻辑来遍历集合: for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
奥秘在于客户端自身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。
客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。
首先看看.util.Iterator接口的定义:
public interface Iterator { boolean hasNext(); Object next(); void remove(); }依赖前两个方法就能完成遍历,典型的代码如下:
for(Iterator it = c.iterator(); it.hasNext(); ) { Object o = it.next(); // 对o的操作... }每一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回 SetIterator,Tree可能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种 Iterator,它只需要获得这个Iterator接口即可,这就是面向对象的威力。
所有集合类都实现了 Collection 接口,而 Collection 继承了 Iterable 接口。
1 public interface Collection<E> extends Iterable<E> { }
而在具体的实现类中(比如 ArrayList),则在内部维护了一个 Itr 内部类,该类继承了 Iterator 接口,它的hasNext() 和 next() 方法是和 ArrayList 实现相耦合的。当调用 ArrayList 对象的 iterator() 方法的时候,返回该类 Itr 的一个实例,从而实现遍历 ArrayList 的功能。
1 /** 2 * An optimized version of AbstractList.Itr 3 */ 4 private class Itr implements Iterator{ 5 int cursor; // index of next element to return 6 int lastRet = -1; // index of last element returned; -1 if no such 7 int expectedModCount = modCount; 8 9 public boolean hasNext() {10 return cursor != size;11 }12 13 @SuppressWarnings("unchecked")14 public E next() {15 checkForComodification();16 int i = cursor;17 if (i >= size)18 throw new NoSuchElementException();19 Object[] elementData = ArrayList.this.elementData;20 if (i >= elementData.length)21 throw new ConcurrentModificationException();22 cursor = i + 1;23 return (E) elementData[lastRet = i];24 }25 26 public void remove() {27 if (lastRet < 0)28 throw new IllegalStateException();29 checkForComodification();30 31 try {32 ArrayList.this.remove(lastRet);33 cursor = lastRet;34 lastRet = -1;35 expectedModCount = modCount;36 } catch (IndexOutOfBoundsException ex) {37 throw new ConcurrentModificationException();38 }39 }
在遍历元素或者删除元素时,必须要进行next()方法,要不然,迭代器不能正常运行:如