迭代器模式:集合遍历的优雅实现与应用场景

📅 2026/8/11 12:24:51
迭代器模式:集合遍历的优雅实现与应用场景
1. 迭代器模式集合遍历的优雅解法在软件开发中我们经常需要处理各种集合对象——数组、列表、哈希表等。直接暴露集合内部结构让客户端代码实现遍历逻辑会导致几个明显问题客户端与集合实现紧密耦合、同一集合可能有多种遍历方式、集合内部变化会波及所有客户端代码。迭代器模式正是为解决这些问题而生。迭代器模式Iterator Pattern属于行为型设计模式它提供一种方法顺序访问一个聚合对象中的各个元素而又不暴露该对象的内部表示。想象你去图书馆借书——你不需要知道书籍是如何在书架排列的只需要通过图书管理员迭代器按顺序获取即可。这种无需知道细节只管使用的思想正是迭代器模式的核心。从技术实现看迭代器模式主要包含两个关键角色迭代器接口Iterator定义访问和遍历元素的接口通常包含hasNext()、next()等方法具体迭代器ConcreteIterator实现迭代器接口负责管理当前遍历位置Java集合框架中的Iterator就是该模式的经典实现。比如ArrayList的iterator()方法返回的Itr内部类就是具体迭代器实现。这种设计让客户端可以用统一方式遍历不同集合而无需关心底层是数组还是链表。关键提示迭代器模式特别适合以下场景需要以不同方式遍历集合对象时需要统一遍历接口支持多种聚合对象时需要隐藏集合复杂内部结构时2. 迭代器模式深度解析2.1 模式结构与UML图解标准的迭代器模式包含以下核心组件Aggregate抽象聚合 |__ ConcreteAggregate具体聚合 |__ createIterator(): Iterator Iterator抽象迭代器 |__ ConcreteIterator具体迭代器 |__ hasNext(): boolean |__ next(): Object以Java集合为例对应关系为Aggregate → Collection接口ConcreteAggregate → ArrayList等实现类Iterator → java.util.Iterator接口ConcreteIterator → ArrayList.Itr等内部类这种结构实现了两个重要解耦遍历算法与集合实现解耦客户端代码与集合内部结构解耦2.2 迭代器实现方式对比不同语言对迭代器的实现各有特色Java风格ListString list Arrays.asList(A, B, C); IteratorString it list.iterator(); while(it.hasNext()) { System.out.println(it.next()); }C STL风格std::vectorstd::string vec{A, B, C}; for(auto it vec.begin(); it ! vec.end(); it) { std::cout *it std::endl; }JavaScript ES6风格const arr [A, B, C]; const it arr[Symbol.iterator](); let result it.next(); while(!result.done) { console.log(result.value); result it.next(); }虽然语法各异但核心思想一致将集合的遍历行为抽象为独立对象。2.3 迭代器模式的进阶变体除了标准实现迭代器模式还有几种实用变体内部迭代器 集合自身控制迭代过程客户端通过回调处理元素。如Java的forEachlist.forEach(item - System.out.println(item));双向迭代器 支持向前和向后遍历常见于链表实现ListIteratorString it list.listIterator(); it.next(); // 向前 it.previous(); // 向后线程安全迭代器 通过快照或锁机制保证并发安全如CopyOnWriteArrayList的迭代器。惰性迭代器 按需计算下一个元素常见于流式处理和大数据集。3. 手把手实现迭代器模式3.1 基础实现示例我们实现一个简单的书籍集合和对应迭代器// 迭代器接口 public interface IteratorT { boolean hasNext(); T next(); } // 聚合接口 public interface AggregateT { IteratorT createIterator(); } // 具体聚合 public class BookShelf implements AggregateBook { private Book[] books; private int last 0; public BookShelf(int size) { this.books new Book[size]; } public Book getBookAt(int index) { return books[index]; } public void appendBook(Book book) { this.books[last] book; } public int getLength() { return last; } Override public IteratorBook createIterator() { return new BookShelfIterator(this); } } // 具体迭代器 public class BookShelfIterator implements IteratorBook { private BookShelf bookShelf; private int index 0; public BookShelfIterator(BookShelf bookShelf) { this.bookShelf bookShelf; } Override public boolean hasNext() { return index bookShelf.getLength(); } Override public Book next() { return bookShelf.getBookAt(index); } }使用示例BookShelf shelf new BookShelf(4); shelf.appendBook(new Book(Design Patterns)); shelf.appendBook(new Book(Clean Code)); IteratorBook it shelf.createIterator(); while(it.hasNext()) { System.out.println(it.next().getName()); }3.2 实现细节与技巧迭代器状态管理 迭代器需要维护当前遍历位置对于并发修改敏感的集合如ArrayList需要在创建迭代器时记录modCount遍历时检查是否一致不一致则抛出ConcurrentModificationException。空迭代器实现 对于空集合可以返回一个特殊的空迭代器实例避免创建多余对象public static T IteratorT emptyIterator() { return new IteratorT() { Override public boolean hasNext() { return false; } Override public T next() { throw new NoSuchElementException(); } }; }支持remove操作 可以在迭代器接口中添加remove方法但要注意实现时检查是否支持删除只能在next之后调用一次更新底层集合和迭代器状态泛型化设计 使用泛型可以让迭代器更类型安全避免强制类型转换。4. 实战中的迭代器模式4.1 Java集合框架中的应用Java集合框架是迭代器模式的教科书级实现。关键设计要点Iterable接口public interface IterableT { IteratorT iterator(); default void forEach(Consumer? super T action) { ... } }所有集合实现该接口支持增强for循环for (String item : list) { ... }Iterator接口public interface IteratorE { boolean hasNext(); E next(); default void remove() { ... } default void forEachRemaining(Consumer? super E action) { ... } }ListIterator扩展public interface ListIteratorE extends IteratorE { boolean hasPrevious(); E previous(); int nextIndex(); int previousIndex(); void set(E e); void add(E e); }4.2 自定义集合的迭代器实现假设我们要实现一个树形结构的迭代器可以考虑两种遍历方式深度优先迭代器public class DepthFirstIteratorT implements IteratorT { private StackTreeNodeT stack new Stack(); public DepthFirstIterator(TreeNodeT root) { if (root ! null) stack.push(root); } Override public boolean hasNext() { return !stack.isEmpty(); } Override public T next() { TreeNodeT current stack.pop(); // 右子树先入栈保证左子树先出 if (current.right ! null) stack.push(current.right); if (current.left ! null) stack.push(current.left); return current.value; } }广度优先迭代器public class BreadthFirstIteratorT implements IteratorT { private QueueTreeNodeT queue new LinkedList(); public BreadthFirstIterator(TreeNodeT root) { if (root ! null) queue.offer(root); } Override public boolean hasNext() { return !queue.isEmpty(); } Override public T next() { TreeNodeT current queue.poll(); if (current.left ! null) queue.offer(current.left); if (current.right ! null) queue.offer(current.right); return current.value; } }4.3 性能优化实践原始类型特化 避免装箱拆箱开销可以创建IntIterator等特化接口public interface IntIterator { boolean hasNext(); int nextInt(); }视图迭代器 对子集合创建视图迭代器而非复制元素public class SubListIteratorE implements IteratorE { private final ListE list; private int cursor; private final int end; public SubListIterator(ListE list, int start, int end) { this.list list; this.cursor start; this.end end; } // 实现省略... }并行迭代 对于大型集合可以实现并行迭代器public class ParallelIteratorE implements IteratorE { private final SpliteratorE spliterator; private IteratorE current; public ParallelIterator(CollectionE collection) { this.spliterator collection.spliterator(); } Override public boolean hasNext() { if (current null || !current.hasNext()) { current StreamSupport.stream(spliterator, true) .limit(1000) // 分批处理 .iterator(); } return current.hasNext(); } Override public E next() { return current.next(); } }5. 常见问题与解决方案5.1 迭代器失效问题问题现象ListString list new ArrayList(); list.add(A); IteratorString it list.iterator(); list.add(B); // 结构修改 System.out.println(it.next()); // 抛出ConcurrentModificationException解决方案使用并发集合如CopyOnWriteArrayList在迭代期间避免直接修改原集合通过迭代器自身的方法修改如iterator.remove()5.2 嵌套迭代问题问题代码SetSetInteger sets ...; for (SetInteger inner : sets) { for (Integer num : inner) { if (num target) { inner.remove(num); // 可能抛出异常 } } }正确做法sets.forEach(inner - inner.removeIf(num - num target));5.3 自定义迭代器的线程安全实现线程安全迭代器的几种方式快照迭代器public class SnapshotIteratorE implements IteratorE { private final E[] snapshot; private int cursor; public SnapshotIterator(CollectionE collection) { this.snapshot (E[]) collection.toArray(); } // 常规实现... }同步控制迭代器public class SynchronizedIteratorE implements IteratorE { private final IteratorE delegate; private final Object lock; public SynchronizedIterator(IteratorE delegate, Object lock) { this.delegate delegate; this.lock lock; } Override public boolean hasNext() { synchronized(lock) { return delegate.hasNext(); } } Override public E next() { synchronized(lock) { return delegate.next(); } } }5.4 内存泄漏风险问题场景public class DataHolder { private static ListListener listeners new ArrayList(); public static IteratorListener getListeners() { return listeners.iterator(); } }风险点迭代器可能持有集合引用阻止GC回收解决方案使用弱引用或软引用提供迭代器时返回副本而非原集合的迭代器明确文档说明迭代器的生命周期6. 现代语言中的迭代器模式演进6.1 Java Stream APIJava 8引入的Stream可以看作迭代器模式的升级版list.stream() .filter(s - s.length() 3) .map(String::toUpperCase) .forEach(System.out::println);特点链式调用惰性求值并行处理支持6.2 JavaScript迭代协议ES6引入的迭代协议更加灵活const myIterable { [Symbol.iterator]: function* () { yield 1; yield 2; yield 3; } }; for (const value of myIterable) { console.log(value); }6.3 Kotlin序列(Sequence)Kotlin的Sequence提供类似Java Stream的操作sequenceOf(1, 2, 3) .filter { it 1 } .map { it * 2 } .forEach { println(it) }特点与集合API统一更好的IDE支持更简洁的语法6.4 Rust迭代器Rust的迭代器是零成本抽象let v vec![1, 2, 3]; let sum: i32 v.iter() .map(|x| x 1) .sum();特点编译时展开无运行时开销所有权机制保证安全7. 设计模式组合应用7.1 迭代器组合模式处理树形结构的经典组合// 组合模式组件 interface Component { IteratorComponent createIterator(); } // 叶子节点 class Leaf implements Component { public IteratorComponent createIterator() { return Collections.emptyIterator(); } } // 复合节点 class Composite implements Component { private ListComponent children new ArrayList(); public IteratorComponent createIterator() { return new CompositeIterator(children.iterator()); } } // 复合迭代器 class CompositeIterator implements IteratorComponent { private StackIteratorComponent stack new Stack(); public CompositeIterator(IteratorComponent iterator) { stack.push(iterator); } Override public boolean hasNext() { if (stack.isEmpty()) return false; IteratorComponent it stack.peek(); if (it.hasNext()) { return true; } else { stack.pop(); return hasNext(); } } Override public Component next() { IteratorComponent it stack.peek(); Component component it.next(); stack.push(component.createIterator()); return component; } }7.2 迭代器访问者模式实现复杂遍历逻辑interface Visitor { void visit(Element element); } class ElementIterator { public void iterate(CollectionElement collection, Visitor visitor) { for (Element element : collection) { visitor.visit(element); if (element instanceof Container) { iterate(((Container)element).getChildren(), visitor); } } } }7.3 迭代器工厂模式创建不同类型的迭代器interface IteratorFactory { T IteratorT createIterator(CollectionT collection); } class RandomIteratorFactory implements IteratorFactory { public T IteratorT createIterator(CollectionT collection) { ListT shuffled new ArrayList(collection); Collections.shuffle(shuffled); return shuffled.iterator(); } }8. 测试迭代器实现8.1 单元测试要点测试迭代器时应关注遍历顺序是否正确hasNext()是否准确反映状态next()是否按预期返回元素并发修改是否被正确检测边缘情况空集合、单元素集合等示例测试Test void testIterator() { ListString list Arrays.asList(A, B, C); IteratorString it list.iterator(); assertTrue(it.hasNext()); assertEquals(A, it.next()); assertTrue(it.hasNext()); assertEquals(B, it.next()); assertTrue(it.hasNext()); assertEquals(C, it.next()); assertFalse(it.hasNext()); assertThrows(NoSuchElementException.class, () - it.next()); }8.2 性能测试指标遍历耗时测量完整遍历所需时间内存占用监控迭代过程中的内存变化并发性能多线程下的吞吐量和正确性GC影响迭代器创建/销毁对垃圾回收的影响JMH基准测试示例Benchmark BenchmarkMode(Mode.AverageTime) OutputTimeUnit(TimeUnit.MILLISECONDS) public void testArrayListIteration(Blackhole bh) { ListInteger list IntStream.range(0, 1000000) .boxed() .collect(Collectors.toList()); for (Integer num : list) { bh.consume(num); } }8.3 测试替身应用使用Mock对象测试迭代器使用者Test void testIteratorUser() { SuppressWarnings(unchecked) IteratorString mockIterator mock(Iterator.class); when(mockIterator.hasNext()).thenReturn(true, true, false); when(mockIterator.next()).thenReturn(A, B); IteratorUser user new IteratorUser(); int count user.process(mockIterator); assertEquals(2, count); verify(mockIterator, times(2)).next(); }9. 反模式与误用警示9.1 常见误用场景暴露内部状态// 错误直接返回内部数组的迭代器 public IteratorT getIterator() { return Arrays.stream(internalArray).iterator(); }忽略并发修改// 危险可能抛出ConcurrentModificationException for (String item : list) { if (condition) { list.remove(item); } }资源未关闭// 问题迭代器可能持有资源 try (LineIterator it FileUtils.lineIterator(file)) { while (it.hasNext()) { process(it.nextLine()); } } // 自动关闭9.2 性能陷阱多层迭代性能问题// O(n^2)复杂度 for (TypeA a : collectionA) { for (TypeB b : collectionB) { if (a.relatedTo(b)) { // ... } } }优化方案使用索引或哈希加速查找预先处理数据减少嵌套层级考虑使用并行流装箱拆箱开销ListInteger list ...; int sum 0; for (Integer num : list) { // 自动拆箱 sum num; }优化方案使用原始类型特化集合如Eclipse Collections考虑使用Stream的mapToInt等操作9.3 设计警示避免过度设计 对于简单集合遍历直接使用语言内置的for-each语法通常比自定义迭代器更合适。注意迭代器生命周期 长时间持有的迭代器可能导致内存泄漏数据过期并发问题考虑不可变迭代器 对于只读场景返回不可变迭代器更安全public IteratorT getUnmodifiableIterator() { return Collections.unmodifiableList(innerList).iterator(); }10. 行业应用案例分析10.1 数据库结果集遍历JDBC ResultSet本质上是迭代器模式的实现try (ResultSet rs stmt.executeQuery(sql)) { while (rs.next()) { String name rs.getString(name); // 处理数据 } }优化实践使用RowSet包装实现离线迭代分批获取控制内存使用使用try-with-resources确保关闭10.2 大型文件处理处理GB级文本文件的迭代器实现public class BigFileIterator implements IteratorString { private BufferedReader reader; private String nextLine; public BigFileIterator(Path file) throws IOException { this.reader Files.newBufferedReader(file); this.nextLine reader.readLine(); } Override public boolean hasNext() { if (nextLine null) { close(); return false; } return true; } Override public String next() { if (!hasNext()) throw new NoSuchElementException(); String current nextLine; try { nextLine reader.readLine(); } catch (IOException e) { close(); throw new UncheckedIOException(e); } return current; } private void close() { try { if (reader ! null) reader.close(); } catch (IOException ignored) {} } }10.3 分页查询迭代实现透明分页遍历public class PagingIteratorT implements IteratorT { private final int pageSize; private final FunctionInteger, ListT pageFetcher; private ListT currentPage; private int currentIndex; private int currentPageNum; public PagingIterator(int pageSize, FunctionInteger, ListT pageFetcher) { this.pageSize pageSize; this.pageFetcher pageFetcher; loadPage(0); } private void loadPage(int pageNum) { currentPage pageFetcher.apply(pageNum); currentIndex 0; currentPageNum pageNum; } Override public boolean hasNext() { if (currentIndex currentPage.size()) { return true; } // 尝试加载下一页 ListT nextPage pageFetcher.apply(currentPageNum 1); if (!nextPage.isEmpty()) { currentPage nextPage; currentIndex 0; currentPageNum; return true; } return false; } Override public T next() { if (!hasNext()) throw new NoSuchElementException(); return currentPage.get(currentIndex); } }10.4 跨系统数据聚合合并多个数据源的迭代器public class MultiSourceIteratorT implements IteratorT { private final ListIteratorT iterators; private int currentIndex; public MultiSourceIterator(ListIteratorT iterators) { this.iterators new ArrayList(iterators); this.currentIndex 0; } Override public boolean hasNext() { advanceToNext(); return currentIndex iterators.size(); } Override public T next() { if (!hasNext()) throw new NoSuchElementException(); return iterators.get(currentIndex).next(); } private void advanceToNext() { while (currentIndex iterators.size() !iterators.get(currentIndex).hasNext()) { currentIndex; } } }11. 迭代器模式演进趋势11.1 响应式编程中的迭代器在响应式流如Reactor、RxJava中迭代器演变为Publisher-Subscriber模式Flux.range(1, 10) .map(i - i * 2) .subscribe(System.out::println);特点推送模式取代拉取模式背压支持异步非阻塞11.2 函数式编程影响现代语言更倾向于使用高阶函数替代显式迭代器list.filter { it 5 } .map { it * 2 } .forEach { println(it) }优势声明式风格链式调用并行化简单11.3 语言集成查询(LINQ)C#的LINQ将迭代器模式提升到语言层面var results from item in collection where item.Value 5 orderby item.Date select item.Name;11.4 无限数据流处理迭代器模式扩展到无限流处理public class RandomNumberIterator implements IteratorDouble { Override public boolean hasNext() { return true; // 永远有下一个 } Override public Double next() { return Math.random(); } }应用场景传感器数据流实时日志处理金融行情推送12. 设计权衡与决策指南12.1 何时使用迭代器模式推荐场景需要支持多种遍历方式时需要统一接口遍历不同结构时需要隐藏集合复杂内部实现时处理大型或分布式数据集时12.2 何时避免迭代器模式不推荐场景集合结构极其简单且稳定性能要求极高需要直接访问内部结构遍历逻辑极其简单且不会变化12.3 与其他模式的关系与工厂方法模式 迭代器通常通过工厂方法如collection.iterator()创建与组合模式 常用于遍历递归结构如树形菜单与访问者模式 迭代器负责遍历访问者负责操作12.4 性能考量内存效率迭代器本身有对象创建开销某些实现如快照迭代器会复制数据遍历效率链表结构的随机访问性能差大数据集考虑分批或并行处理并发考量同步迭代器影响吞吐量考虑使用并发集合或副本13. 经典实现源码分析13.1 Java ArrayList迭代器关键实现细节private class Itr implements IteratorE { int cursor; // 下一个元素索引 int lastRet -1; // 最后返回的元素索引 int expectedModCount modCount; 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(); } } final void checkForComodification() { if (modCount ! expectedModCount) throw new ConcurrentModificationException(); } }设计亮点快速失败机制fail-fast支持遍历中安全删除轻量级实现不复制数据13.2 Google Guava UnmodifiableIterator不可变迭代器实现public abstract class UnmodifiableIteratorE implements IteratorE { Deprecated Override public final void remove() { throw new UnsupportedOperationException(); } // 其他方法由子类实现 }典型子类static class ArrayItrE extends UnmodifiableIteratorE { final E[] array; int index; ArrayItr(E[] array) { this.array array; } Override public boolean hasNext() { return index array.length; } Override public E next() { if (!hasNext()) { throw new NoSuchElementException(); } return array[index]; } }13.3 Eclipse Collections原始类型迭代器优化范例IntIteratorpublic interface IntIterator { boolean hasNext(); int next(); default void remove() { throw new UnsupportedOperationException(remove); } default void forEachRemaining(IntProcedure procedure) { while (hasNext()) { procedure.value(next()); } } }优势避免装箱拆箱特化操作提升性能内存更紧凑14. 扩展思考与创新应用14.1 基于迭代器的撤销/重做利用迭代器状态实现命令模式public class CommandHistory { private ListCommand history new ArrayList(); private int cursor 0; public void execute(Command cmd) { cmd.execute(); // 移除cursor之后的命令 history.subList(cursor, history.size()).clear(); history.add(cmd); cursor; } public void undo() { if (cursor 0) { Command cmd history.get(--cursor); cmd.undo(); } } public void redo() { if (cursor history.size()) { Command cmd history.get(cursor); cmd.execute(); } } }14.2 迭代器模式与事件溯源将集合状态变化记录为事件流public class EventSourcedCollectionT { private ListT state new ArrayList(); private ListCollectionEvent events new ArrayList(); public IteratorCollectionEvent eventIterator() { return events.iterator(); } public void add(T item) { state.add(item); events.add(new AddEvent(item)); } // 其他方法... }14.3 分布式迭代器跨节点数据聚合迭代public class DistributedIteratorT implements IteratorT { private ListIteratorT shardIterators; private int currentShard; public DistributedIterator(ListDataSource shards) { this.shardIterators shards.stream() .map(DataSource::iterator) .collect(Collectors.toList()); this.currentShard 0; } Override public boolean hasNext() { advanceIfNeeded(); return currentShard shardIterators.size(); } Override public T next() { if (!hasNext()) throw new NoSuchElementException(); return shardIterators.get(currentShard).next(); } private void advanceIfNeeded() { while (currentShard shardIterators.size() !shardIterators.get(currentShard).hasNext()) { currentShard; } } }14.4 迭代器模式与机器学习批处理数据迭代class BatchIterator: def __init__(self, data, batch_size32, shuffleTrue): self.data data self.batch_size batch_size self.shuffle shuffle self.index 0 def __iter__(self): if self.shuffle: np.random.shuffle(self.data) self.index 0 return self def __next__(self): if self.index len(self.data): raise StopIteration batch self.data[self.index:self.indexself.batch_size] self.index self.batch_size return batch15. 个人实践心得在实际项目中应用迭代器模式有几个特别值得分享的经验防御性拷贝的价值 对于不可变集合在创建迭代器时进行防御性拷贝往往能避免后续很多并发问题。虽然有一定性能开销但在多数场景下值得付出这个代价。组合迭代器的威力 当需要处理多层嵌套数据结构时设计良好的组合迭代器能极大简化客户端代码。我曾实现过一个深度遍历JSON树的迭代器让业务代码从复杂的递归中解放出来。资源管理的教训 早期我曾忽视迭代器持有的资源如数据库连接、文件句柄导致资源泄漏。现在会特别注意实现AutoCloseable接口使用try-with-resources明确文档说明资源责任性能调优的平衡 过度优化迭代器实现有时得不偿失。曾经为了减少对象创建实现了一个复杂的状态机迭代器结果反而降低了可维护性。现在会遵循先保证正确性再考虑简单优化只有性能确实成为瓶颈时才做复杂优化测试的重要性 迭代器实现的边界条件特别多空集合、首元素、末元素、并发修改等。建立全面的测试用例能避免很多生产环境问题我通常会覆盖所有边界条件模拟并发场景进行压力测试函数式编程的启示 现代语言的高阶函数让很多迭代器实现变得不必要。但在需要精细控制遍历过程时自定义迭代器仍是不可替代的工具。关键在于根据场景选择最合适的抽象层级。