设计模式(1)Iterator模式
Iterator是java集合框架的成员,使用了设计模式中的Iterator模式
我们从API中将这种方式提炼出来,并且了解List的设计
Iterator核心设计
1 定义接口
- Iterator
public interface Iterator<E> { boolean hasNext(); E next(); }
- Iterable 用来给实现类继承
public interface Iterable<T> { Iterator<T> iterator(); }
2 然后写一个类实现Iterator,即迭代器, 这个类可以是单独的一个类。在ArryayList的设计里,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;
public boolean hasNext() {
return cursor != size;
}
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];
}
}
3 ArrayList 实现Iterable
public Iterator<E> iterator() {
return new Itr();
}
思考
Q:使用 Iterator 这样写有什么好处呢?
A:引入Iterator后可以将遍历与实现分离开
List<Integer> list = new ArrayList<>();
list.addAll(Arrays.asList(1, 2, 3, 4, 5));
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
显然while
循环并不依赖于ArraysList
的实现。当API编写人员不用数组来实现ArrayList
而是用其他的方式,只要能返回正确的Iterator
实例,hasNext
方法和next
方法可以正常工作。不对上面方法做任何修改,代码都可以正常工作。对于ArrayList
的调用者来说非常方便。
设计模式的作用就是帮助我们编写可复用的类。所谓“可复用”就是指将类实现为“组件”,当一个组件发生改变时,不需要对其他的组件进行修改或者只需要很小的修改即可对应。
这要也就理解为什么示例程序中iterator()
的返回值不是、Itr
而是Iterator
了。
实际上新的API版本中 Iterator还有一些小细节
- 1 刚才我们已经可以看到我们的接口定义使用了泛型,这说明我们例子的版本已经时JDK1.5或者更新,更旧的版本我们就不讨论了。我一般看jdk1.8
- 3 我们可以看到每次调用ArryaList的迭代器
Iterator()
都会new 一个 Itr()。虽然java对象有自动回收机制。但是这里可不可以用工厂模式来获得? -
4 java 8 中接口可以定义defalut方法,且接口和类通过继承来获得(接口的静态方法不能继承)。Iterator接口额外提供了
e.remove()
而 Iterable接口额外提供了foreach()
。最终ArrayList提供的Itr
覆盖了default remove()
方法。ArrayList自己覆盖了foreach()
方法。真正的API里的Iterator做了扩展
- 4.1 Iterator
public interface Iterator<E> { boolean hasNext(); E next(); default void remove() { throw new UnsupportedOperationException("remove"); } /** * behaves as if: * while (hasNext()) * action.accept(next()); * @since 1.8 */ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
- 4.2 Iterable
public interface Iterable<T> { Iterator<T> iterator(); default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } default Spliterator<T> spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } }
-
5 ArrayList和Iterable的继承关系
ArrayList
是AbstractList
的子类,AbstractList
提供了两个迭代器Itr
和ListItr
,但是ArryList
自己重新实现了这两个迭代器。在迭代器的next
和remove
和forEachRemaining
方法中均能抛出ConcurrentModificationException
异常 有兴趣的可以对比下ArrayList自己的Itr和AbstractList的Itr的异同。 -
remove 和 next
-
forEachRemaining