参考:B站UP主动力节点
迭代器模式
定义:提供方法,顺序访问集合对象中的各个元素,而又不暴露对象的内部表示。为遍历不同的集合结构提供统一的接口,分离了集合对象的遍历行为。
tips:Iterator
迭代器本身就是JDK按照该模式设计的迭代器,通常情况下,我们都是直接使用JDK提供的。
此处手撕一个简易版迭代器方便理解:
public interface Iterator{
public boolean hasNext(); // 判断是否有下一个元素
public Object next(); // 获取下一个元素
}
// 容器接口,内部含迭代器
public interface Container {
public Iterator getIterator();
}
// 举例,String[]作为容器
public class NameContainer implements Container{
public String[] names = {"zhangsan", "lisi", "wangwu"};
@Override
public Iterator getIterator(){
return new NameIterator();
}
private class NameIterator implements Iterator{
int index;
@Override
public boolean hasNext(){
if (index < names.length()) return true;
return false;
}
@Override
public Object next(){
if (this.hashNext()) return names[index++];
return null;
}
}
}
测试结果:
public class Test{
public static void main(String[] args) {
Container container = new NameContainer();
for (Iterator iterator = container.getIterator; iterator.hashNext()) {
System.out.println("姓名:" + iterator.next().toString());
}
}
}
源码理解
特地查阅源码之后,确认JDK8中所提供的迭代器与以上手撕版本原理相同。
JDK8中的Iterator
接口:
public interface Iterator<E> {
boolean hasNext();
E next();
// default methods
}
public interface Iterable<T> {
Iterator<T> iterator();
// default methods
}
public interface Collection<E> extends Iterable<E> {
//...
Iterator<E> iterator();
// ...
}
核心仍然是hasNext()
和next()
两个方法,然后在Collection<T>
接口中实现了Iterable<T>
接口。简而言之,就是我们常用的Collection
的子接口List、Set、Queue
都含有迭代器。
然后,可以动动我们的小手,翻阅各个具体实现类中的Iterator是如何实现的,比如ArratList
中,有私有实现类Itr
外,还有ListItr
:
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;
}
@SuppressWarnings("unchecked")
public E next() {...}
public void remove() {...}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {...}
final void checkForComodification() {...}
}
private class ListItr extends Itr implements ListIterator<E> {...}
当然,除特殊情况,一般我们使用Iterator
迭代器的目的就是为了脱离集合本身迭代,而迭代只需要关注本身的hasNext()
和next()
方法即可。
这里我一直强调的是脱离集合本身迭代,意思就是提高代码的可复用性,这里主要是和for
循环做对比,以下内容阐述两者的主要区别。
Iterator和foreach的区别
可以理解为foreach
是Iterator
的简易版,foreach
仅含有迭代功能,而Iterator还含有其他功能,比如remove、add
等,不同集合类含有的Iterator功能可能不同。
Iterator、foreach和for循环的区别
本质区别在于,Iterator
迭代器和foreach
是在集合的副本中迭代,而for
循环是在集合本身循环。以ArrayList
为例,元素都存储在一个Obeject[] elementData
数组中,前两者的遍历对象为Object[] elementData = ArrayList.this.elementData;
,即原数组的副本,而for
循环是直接遍历Obeject[] elementData
本身。
使用上,iterator
和foreach
是按顺序依次搜索,而for
循环是依据索引直接获取指定元素。所以,按顺序存储的结构中,优先使用for
循环,比如ArrayList
;而在不按顺序存储的结构中,只能使用iterator
或foreach
,比如HashSet、map.KeySet()
以及一些链式结构。
我们设计程序时,考虑使用迭代器的主要目的是为了代码的复用性,比如当前集合可能更改为链式结构存储时,遍历功能就可以采用iterator
方便后续维护。