引言:集合遍历的演进之路
在软件开发中,集合遍历是我们每天都要面对的基础操作。从最初的数组索引遍历到现代的流式处理,我们经历了:
原始索引遍历 迭代器模式 内部迭代器 Stream API
然而,即使有了高级API,迭代器模式仍然是理解集合遍历本质的关键。它提供了一种统一的方式访问各种聚合对象中的元素,而无需暴露底层表示。本文将深入解析迭代器模式的原理、实现及高级应用场景。
一、模式定义与核心思想
1.1 官方定义
迭代器模式 (Iterator Pattern):提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
1.2 设计哲学
客户端 迭代器接口 具体迭代器 聚合接口 具体聚合
核心原则:
- 单一职责:将遍历逻辑与集合实现分离
- 开闭原则:新增集合类型不影响遍历代码
- 统一接口:为不同集合提供一致的遍历方式
二、模式结构解析
2.1 UML类图
创建 访问 <<interface>> Iterator +hasNext() : boolean +next() : Object +remove() : void ConcreteIterator -collection: Collection -cursor: int +hasNext() +next() +remove() <<interface>> Aggregate +createIterator() : Iterator ConcreteAggregate -elements: Object[] +createIterator()
2.2 关键角色
角色 | 职责 | Java集合示例 |
---|---|---|
Iterator | 定义遍历接口 | java.util.Iterator |
ConcreteIterator | 实现具体遍历逻辑 | ArrayList.Itr |
Aggregate | 定义创建迭代器接口 | java.lang.Iterable |
ConcreteAggregate | 实现集合创建迭代器 | ArrayList |
三、代码实战:自定义集合实现
3.1 场景描述
实现一个支持多种遍历方式的二维矩阵:
- 行优先遍历(从左到右,从上到下)
- 列优先遍历(从上到下,从左到右)
- 对角线遍历
3.2 核心实现
java
// 迭代器接口
public interface MatrixIterator<T> {
boolean hasNext();
T next();
}
// 矩阵接口
public interface Matrix<T> {
int getRows();
int getColumns();
T get(int row, int col);
MatrixIterator<T> rowMajorIterator();
MatrixIterator<T> columnMajorIterator();
MatrixIterator<T> diagonalIterator();
}
// 具体矩阵实现
public class ArrayMatrix<T> implements Matrix<T> {
private final T[][] data;
public ArrayMatrix(T[][] data) {
this.data = data;
}
@Override
public int getRows() {
return data.length;
}
@Override
public int getColumns() {
return data[0].length;
}
@Override
public T get(int row, int col) {
return data[row][col];
}
// 行优先迭代器
@Override
public MatrixIterator<T> rowMajorIterator() {
return new RowMajorIterator();
}
// 列优先迭代器
@Override
public MatrixIterator<T> columnMajorIterator() {
return new ColumnMajorIterator();
}
// 对角线迭代器
@Override
public MatrixIterator<T> diagonalIterator() {
return new DiagonalIterator();
}
// 行优先迭代器实现
private class RowMajorIterator implements MatrixIterator<T> {
private int row = 0;
private int col = 0;
@Override
public boolean hasNext() {
return row < getRows() && col < getColumns();
}
@Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
T element = get(row, col);
col++;
if (col >= getColumns()) {
col = 0;
row++;
}
return element;
}
}
// 列优先迭代器实现
private class ColumnMajorIterator implements MatrixIterator<T> {
private int row = 0;
private int col = 0;
@Override
public boolean hasNext() {
return col < getColumns() && row < getRows();
}
@Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
T element = get(row, col);
row++;
if (row >= getRows()) {
row = 0;
col++;
}
return element;
}
}
// 对角线迭代器实现
private class DiagonalIterator implements MatrixIterator<T> {
private int diag = 0;
private int pos = 0;
@Override
public boolean hasNext() {
return diag < (getRows() + getColumns() - 1);
}
@Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
int row, col;
if (diag < getRows()) {
row = diag - pos;
col = pos;
} else {
row = getRows() - 1 - pos;
col = diag - getRows() + 1 + pos;
}
T element = get(row, col);
pos++;
if (pos > diag ||
(diag >= getRows() && pos >= getRows() + getColumns() - diag - 1)) {
diag++;
pos = 0;
}
return element;
}
}
}
3.3 客户端使用
java
public class MatrixClient {
public static void main(String[] args) {
Integer[][] matrixData = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
Matrix<Integer> matrix = new ArrayMatrix<>(matrixData);
System.out.println("行优先遍历:");
printIterator(matrix.rowMajorIterator());
System.out.println("\n列优先遍历:");
printIterator(matrix.columnMajorIterator());
System.out.println("\n对角线遍历:");
printIterator(matrix.diagonalIterator());
}
private static void printIterator(MatrixIterator<?> iterator) {
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
/* 输出:
行优先遍历:
1 2 3 4 5 6 7 8 9
列优先遍历:
1 4 7 2 5 8 3 6 9
对角线遍历:
1 2 4 3 5 7 6 8 9
*/
3.4 遍历过程可视化
1-2-3-4-5-6-7-8-9 1-4-7-2-5-8-3-6-9 1-2-4-3-5-7-6-8-9 行优先遍历 顺序访问 列优先遍历 跨行访问 对角线遍历 斜向访问
四、迭代器模式进阶技巧
4.1 线程安全迭代器
java
public class SafeIterator<T> implements Iterator<T> {
private final Object lock = new Object();
private final Iterator<T> delegate;
public SafeIterator(Iterator<T> delegate) {
this.delegate = delegate;
}
@Override
public boolean hasNext() {
synchronized (lock) {
return delegate.hasNext();
}
}
@Override
public T next() {
synchronized (lock) {
return delegate.next();
}
}
@Override
public void remove() {
synchronized (lock) {
delegate.remove();
}
}
}
4.2 过滤迭代器
java
public class FilterIterator<T> implements Iterator<T> {
private final Iterator<T> source;
private final Predicate<T> filter;
private T nextElement;
private boolean hasNext;
public FilterIterator(Iterator<T> source, Predicate<T> filter) {
this.source = source;
this.filter = filter;
findNext();
}
private void findNext() {
while (source.hasNext()) {
T candidate = source.next();
if (filter.test(candidate)) {
nextElement = candidate;
hasNext = true;
return;
}
}
hasNext = false;
}
@Override
public boolean hasNext() {
return hasNext;
}
@Override
public T next() {
if (!hasNext) throw new NoSuchElementException();
T result = nextElement;
findNext();
return result;
}
}
// 使用示例
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Iterator<Integer> evenIterator = new FilterIterator<>(
numbers.iterator(),
n -> n % 2 == 0
);
4.3 分页迭代器
java
public class PagingIterator<T> implements Iterator<List<T>> {
private final Iterator<T> source;
private final int pageSize;
public PagingIterator(Iterator<T> source, int pageSize) {
this.source = source;
this.pageSize = pageSize;
}
@Override
public boolean hasNext() {
return source.hasNext();
}
@Override
public List<T> next() {
if (!hasNext()) throw new NoSuchElementException();
List<T> page = new ArrayList<>(pageSize);
for (int i = 0; i < pageSize && source.hasNext(); i++) {
page.add(source.next());
}
return page;
}
}
// 使用示例
List<Integer> bigList = IntStream.range(0, 1000).boxed().collect(Collectors.toList());
Iterator<List<Integer>> pageIterator = new PagingIterator<>(bigList.iterator(), 100);
while (pageIterator.hasNext()) {
List<Integer> page = pageIterator.next();
processPage(page);
}
五、应用场景分析
5.1 典型应用场景
场景 | 迭代器应用 | 优势 |
---|---|---|
集合框架 | Java集合遍历 | 统一访问接口 |
文件系统 | 目录遍历 | 隐藏文件系统差异 |
数据库 | 结果集遍历 | 抽象数据库访问 |
树形结构 | 多种遍历算法 | 解耦结构与遍历 |
流处理 | 数据管道 | 支持链式操作 |
5.2 使用时机判断
当出现以下情况时考虑迭代器模式:
- 需要统一访问不同聚合结构
- 需要支持多种遍历方式
- 需要隐藏聚合的内部结构
- 需要为聚合提供遍历接口
5.3 不适用场景
- 简单数组或列表遍历
- 性能极度敏感的场景
- 只需要顺序访问的不可变集合
六、模式优劣辩证
6.1 优势 ✅
35% 25% 20% 15% 5% 迭代器模式优势 解耦集合与遍历 多种遍历支持 统一访问接口 延迟加载支持 开闭原则支持
6.2 劣势 ❌
- 性能开销:比直接索引访问慢
- 复杂性增加:简单场景过度设计
- 并发修改问题:迭代中修改集合导致异常
- 单向遍历限制:标准迭代器只支持单向移动
七、与其他模式的关系
7.1 迭代器模式 vs 访问者模式
遍历元素 对元素执行操作 迭代器模式 访问者模式
- 协同关系:迭代器负责遍历,访问者负责操作
- 区别 :
- 迭代器:关注元素访问顺序
- 访问者:关注元素操作逻辑
7.2 迭代器模式 vs 组合模式
维度 | 迭代器模式 | 组合模式 |
---|---|---|
目的 | 遍历元素 | 构建树形结构 |
关注点 | 访问顺序 | 结构组织 |
典型配合 | 常遍历组合结构 | 常提供迭代器 |
八、在Java集合框架中的应用
8.1 迭代器接口演进
Enumeration Iterator ListIterator Spliterator
8.2 ArrayList迭代器实现
java
// ArrayList内部迭代器
private class Itr implements Iterator<E> {
int cursor; // 下一个元素索引
int lastRet = -1; // 最后返回的元素索引
int expectedModCount = modCount; // 并发修改检查
public boolean hasNext() {
return cursor != size;
}
public E next() {
checkForComodification();
int i = cursor;
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
8.3 Java 8 Spliterator
java
public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super T> action);
Spliterator<T> trySplit();
long estimateSize();
int characteristics();
}
// 使用示例
List<String> list = Arrays.asList("a", "b", "c");
Spliterator<String> spliterator = list.spliterator();
// 顺序处理
spliterator.forEachRemaining(System.out::println);
// 并行处理
spliterator.trySplit().forEachRemaining(System.out::println);
九、最佳实践指南
9.1 设计建议
-
使用Iterator而不是直接访问
java// 好 for (Iterator<Item> it = collection.iterator(); it.hasNext(); ) { Item item = it.next(); // ... } // 更好 (Java 5+) for (Item item : collection) { // ... }
-
支持fail-fast机制
javapublic class SafeIterable<T> implements Iterable<T> { private final List<T> data = new ArrayList<>(); private volatile int modCount = 0; @Override public Iterator<T> iterator() { return new SafeIterator<>(data.iterator(), modCount); } private class SafeIterator implements Iterator<T> { private final Iterator<T> delegate; private final int expectedModCount; public SafeIterator(Iterator<T> delegate, int modCount) { this.delegate = delegate; this.expectedModCount = modCount; } private void checkModification() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } @Override public boolean hasNext() { checkModification(); return delegate.hasNext(); } // next() 和 remove() 类似 } }
9.2 性能优化
-
随机访问优化
javapublic class RandomAccessIterator<T> implements Iterator<T> { private final RandomAccess randomAccess; private final int size; private int index = 0; public RandomAccessIterator(List<T> list) { if (!(list instanceof RandomAccess)) { throw new IllegalArgumentException("List must support random access"); } this.randomAccess = (RandomAccess) list; this.size = list.size(); } @Override public boolean hasNext() { return index < size; } @Override public T next() { return ((List<T>) randomAccess).get(index++); } }
-
延迟加载迭代器
javapublic class LazyIterator<T> implements Iterator<T> { private final Supplier<T> supplier; private T next; public LazyIterator(Supplier<T> supplier) { this.supplier = supplier; advance(); } private void advance() { next = supplier.get(); } @Override public boolean hasNext() { return next != null; } @Override public T next() { if (next == null) throw new NoSuchElementException(); T result = next; advance(); return result; } }
9.3 遍历策略对比
策略 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
顺序迭代 | O(n) | O(1) | 链表、文件流 |
随机访问 | O(1) | O(1) | 数组、ArrayList |
分页迭代 | O(n) | O(pageSize) | 大数据集 |
并行迭代 | O(n/p) | O§ | 多核处理器 |
十、总结:迭代器模式的核心价值
迭代器模式通过解耦遍历实现了:
独立演化 独立演化 简化客户端 集合实现 系统灵活性 遍历算法 统一接口 代码可维护性
设计启示 :
将遍历视为独立于集合结构的操作,让集合专注存储,迭代器专注访问
正如《设计模式》作者GoF所强调:
"迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示"
扩展思考:
- 如何在分布式系统中实现迭代器?
- 迭代器模式如何与响应式编程结合?
- 如何设计支持双向遍历的迭代器?
附录:Java迭代器发展史
版本 | 特性 | 代表类/接口 |
---|---|---|
JDK 1.0 | 基本枚举 | Enumeration |
JDK 1.2 | 标准迭代器 | Iterator |
JDK 1.5 | 增强for循环 | Iterable |
JDK 1.5 | 双向迭代 | ListIterator |
JDK 8 | 并行迭代 | Spliterator |
JDK 8 | 流式迭代 | Stream |
迭代器模式是构建灵活、可扩展集合框架的基石,其设计思想深刻影响了现代编程语言的数据处理范式。