迭代器模式:集合遍历的统一之道

引言:集合遍历的演进之路

在软件开发中,集合遍历是我们每天都要面对的基础操作。从最初的数组索引遍历到现代的流式处理,我们经历了:
原始索引遍历 迭代器模式 内部迭代器 Stream API

然而,即使有了高级API,迭代器模式仍然是理解集合遍历本质的关键。它提供了一种统一的方式访问各种聚合对象中的元素,而无需暴露底层表示。本文将深入解析迭代器模式的原理、实现及高级应用场景。


一、模式定义与核心思想

1.1 官方定义

迭代器模式 (Iterator Pattern):提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

1.2 设计哲学

客户端 迭代器接口 具体迭代器 聚合接口 具体聚合

核心原则

  1. 单一职责:将遍历逻辑与集合实现分离
  2. 开闭原则:新增集合类型不影响遍历代码
  3. 统一接口:为不同集合提供一致的遍历方式

二、模式结构解析

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 使用时机判断

当出现以下情况时考虑迭代器模式:

  1. 需要统一访问不同聚合结构
  2. 需要支持多种遍历方式
  3. 需要隐藏聚合的内部结构
  4. 需要为聚合提供遍历接口

5.3 不适用场景

  1. 简单数组或列表遍历
  2. 性能极度敏感的场景
  3. 只需要顺序访问的不可变集合

六、模式优劣辩证

6.1 优势 ✅

35% 25% 20% 15% 5% 迭代器模式优势 解耦集合与遍历 多种遍历支持 统一访问接口 延迟加载支持 开闭原则支持

6.2 劣势 ❌

  1. 性能开销:比直接索引访问慢
  2. 复杂性增加:简单场景过度设计
  3. 并发修改问题:迭代中修改集合导致异常
  4. 单向遍历限制:标准迭代器只支持单向移动

七、与其他模式的关系

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 设计建议

  1. 使用Iterator而不是直接访问

    java 复制代码
    // 好
    for (Iterator<Item> it = collection.iterator(); it.hasNext(); ) {
        Item item = it.next();
        // ...
    }
    
    // 更好 (Java 5+)
    for (Item item : collection) {
        // ...
    }
  2. 支持fail-fast机制

    java 复制代码
    public 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 性能优化

  1. 随机访问优化

    java 复制代码
    public 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++);
        }
    }
  2. 延迟加载迭代器

    java 复制代码
    public 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) 多核处理器

十、总结:迭代器模式的核心价值

迭代器模式通过解耦遍历实现了:
独立演化 独立演化 简化客户端 集合实现 系统灵活性 遍历算法 统一接口 代码可维护性

设计启示
将遍历视为独立于集合结构的操作,让集合专注存储,迭代器专注访问

正如《设计模式》作者GoF所强调:

"迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示"


扩展思考

  1. 如何在分布式系统中实现迭代器?
  2. 迭代器模式如何与响应式编程结合?
  3. 如何设计支持双向遍历的迭代器?

附录:Java迭代器发展史

版本 特性 代表类/接口
JDK 1.0 基本枚举 Enumeration
JDK 1.2 标准迭代器 Iterator
JDK 1.5 增强for循环 Iterable
JDK 1.5 双向迭代 ListIterator
JDK 8 并行迭代 Spliterator
JDK 8 流式迭代 Stream

迭代器模式是构建灵活、可扩展集合框架的基石,其设计思想深刻影响了现代编程语言的数据处理范式

相关推荐
幻奏岚音几秒前
Java数据结构——第一章Java基础回顾
java·开发语言·jvm·笔记·学习
爬虫程序猿11 分钟前
如何利用 Java 爬虫按关键字搜索 Amazon 商品:实战指南
java·开发语言·爬虫
AI+程序员在路上1 小时前
ABI与API定义及区别
c语言·开发语言·c++
2201_753169471 小时前
implement用法
java·开发语言
Mazeltov&&Iliua3 小时前
JAVA 基础知识(一)
java·开发语言
TomCode先生4 小时前
C# 基础知识总结(带详细文字说明)
开发语言·c#
是紫焅呢4 小时前
F接口基础.go
开发语言·后端·青少年编程·golang·visual studio code
虾球xz4 小时前
CppCon 2017 学习:folly::Function A Non-copyable Alternative to std::function
开发语言·c++·学习
程序员弘羽4 小时前
extern关键字:C/C++跨文件编程利器
c语言·开发语言·c++