Skip to content

迭代器模式(Iterator Pattern) ​

一、模式概述 ​

迭代器模式是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式将遍历行为从集合中分离出来,封装到迭代器对象中。

核心思想:提供统一的接口来遍历不同类型的集合,隐藏集合的内部结构,让客户端代码通过迭代器接口来访问元素,而不需要知道集合的底层实现。

二、角色说明 ​

角色说明
Iterator(抽象迭代器)定义遍历元素的接口(hasNext、next、remove)
ConcreteIterator(具体迭代器)实现迭代器接口,记录遍历的当前位置
Aggregate(抽象集合)定义创建迭代器的接口(createIterator)
ConcreteAggregate(具体集合)实现创建迭代器的接口,返回具体的迭代器

三、Java 集合框架中的迭代器 ​

java
import java.util.*;

/**
 * Java 集合框架已经内置了迭代器模式
 *
 * java.util.Iterator 接口:
 *   - hasNext(): 是否还有下一个元素
 *   - next(): 返回下一个元素
 *   - remove(): 移除当前元素
 *
 * java.lang.Iterable 接口:
 *   - iterator(): 返回迭代器对象
 *   - 支持 for-each 循环
 */
public class JavaIteratorDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));

        // 方式1:使用 Iterator
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String item = it.next();
            System.out.println(item);
        }

        // 方式2:for-each 循环(底层使用迭代器)
        for (String item : list) {
            System.out.println(item);
        }

        // 方式3:Lambda 表达式
        list.forEach(item -> System.out.println(item));
    }
}

四、示例1:自定义集合迭代器 ​

问题场景 ​

实现一个自定义的学生集合,支持正序和倒序遍历。

java
import java.util.ArrayList;
import java.util.List;

// ========== 元素类 ==========

/**
 * 学生类
 */
class Student {
    private String name;
    private int age;
    private double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
    public double getScore() { return score; }

    @Override
    public String toString() {
        return name + "(年龄:" + age + ", 分数:" + score + ")";
    }
}

// ========== 抽象迭代器 ==========

/**
 * 学生迭代器接口
 */
interface StudentIterator {
    boolean hasNext();
    Student next();
    void remove();
}

// ========== 具体迭代器 ==========

/**
 * 正序迭代器
 */
class ForwardStudentIterator implements StudentIterator {
    private final List<Student> students;
    private int position = 0;
    private int lastRetrieved = -1;

    public ForwardStudentIterator(List<Student> students) {
        this.students = students;
    }

    @Override
    public boolean hasNext() {
        return position < students.size();
    }

    @Override
    public Student next() {
        if (!hasNext()) {
            throw new java.util.NoSuchElementException("没有更多元素");
        }
        lastRetrieved = position;
        return students.get(position++);
    }

    @Override
    public void remove() {
        if (lastRetrieved < 0) {
            throw new IllegalStateException("没有可删除的元素");
        }
        students.remove(lastRetrieved);
        position = lastRetrieved;
        lastRetrieved = -1;
    }
}

/**
 * 倒序迭代器
 */
class ReverseStudentIterator implements StudentIterator {
    private final List<Student> students;
    private int position;

    public ReverseStudentIterator(List<Student> students) {
        this.students = students;
        this.position = students.size() - 1;
    }

    @Override
    public boolean hasNext() {
        return position >= 0;
    }

    @Override
    public Student next() {
        if (!hasNext()) {
            throw new java.util.NoSuchElementException("没有更多元素");
        }
        return students.get(position--);
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("倒序迭代器不支持删除操作");
    }
}

/**
 * 过滤迭代器:只返回满足条件的学生
 */
class FilterStudentIterator implements StudentIterator {
    private final StudentIterator iterator;
    private final java.util.function.Predicate<Student> filter;
    private Student nextStudent;
    private boolean hasNextStudent;

    public FilterStudentIterator(StudentIterator iterator,
                                  java.util.function.Predicate<Student> filter) {
        this.iterator = iterator;
        this.filter = filter;
        advance();  // 预加载下一个满足条件的元素
    }

    private void advance() {
        hasNextStudent = false;
        while (iterator.hasNext()) {
            Student student = iterator.next();
            if (filter.test(student)) {
                nextStudent = student;
                hasNextStudent = true;
                break;
            }
        }
    }

    @Override
    public boolean hasNext() {
        return hasNextStudent;
    }

    @Override
    public Student next() {
        if (!hasNext()) {
            throw new java.util.NoSuchElementException("没有更多元素");
        }
        Student result = nextStudent;
        advance();
        return result;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("过滤迭代器不支持删除操作");
    }
}

// ========== 抽象集合 ==========

/**
 * 学生集合接口
 */
interface StudentCollection {
    void add(Student student);
    int size();
    StudentIterator createIterator();           // 正序迭代器
    StudentIterator createReverseIterator();    // 倒序迭代器
}

// ========== 具体集合 ==========

/**
 * 学生列表(具体集合)
 */
class StudentList implements StudentCollection {
    private final List<Student> students = new ArrayList<>();

    @Override
    public void add(Student student) {
        students.add(student);
    }

    @Override
    public int size() {
        return students.size();
    }

    @Override
    public StudentIterator createIterator() {
        return new ForwardStudentIterator(students);
    }

    @Override
    public StudentIterator createReverseIterator() {
        return new ReverseStudentIterator(students);
    }
}

// ========== 客户端代码 ==========

public class StudentIteratorDemo {
    public static void main(String[] args) {
        // 创建集合并添加数据
        StudentCollection collection = new StudentList();
        collection.add(new Student("张三", 20, 85.5));
        collection.add(new Student("李四", 22, 92.0));
        collection.add(new Student("王五", 19, 78.0));
        collection.add(new Student("赵六", 21, 95.5));
        collection.add(new Student("孙七", 23, 88.0));

        System.out.println("===== 正序遍历 =====");
        StudentIterator forward = collection.createIterator();
        while (forward.hasNext()) {
            System.out.println(forward.next());
        }

        System.out.println("\n===== 倒序遍历 =====");
        StudentIterator reverse = collection.createReverseIterator();
        while (reverse.hasNext()) {
            System.out.println(reverse.next());
        }

        System.out.println("\n===== 过滤:成绩 >= 90 的学生 =====");
        StudentIterator goodStudents = new FilterStudentIterator(
            collection.createIterator(),
            s -> s.getScore() >= 90.0
        );
        while (goodStudents.hasNext()) {
            System.out.println(goodStudents.next());
        }

        System.out.println("\n===== 使用 Lambda 简化遍历 =====");
        // Java 8+ 可以用 forEachRemaining
        Iterator<Student> it = new ForwardStudentIterator(
            new ArrayList<>(java.util.Arrays.asList(
                new Student("小明", 18, 80),
                new Student("小红", 19, 90)
            ))
        );
        it.forEachRemaining(student -> System.out.println(student));
    }
}

五、示例2:树结构迭代器(二叉树的多种遍历) ​

问题场景 ​

实现二叉树的前序、中序、后序和层序遍历。

java
import java.util.*;

// ========== 二叉树节点 ==========

/**
 * 二叉树节点
 */
class TreeNode<T> {
    T data;
    TreeNode<T> left;
    TreeNode<T> right;

    public TreeNode(T data) {
        this.data = data;
        this.left = null;
        this.right = null;
    }

    public TreeNode(T data, TreeNode<T> left, TreeNode<T> right) {
        this.data = data;
        this.left = left;
        this.right = right;
    }
}

// ========== 树迭代器接口 ==========

/**
 * 树迭代器接口
 */
interface TreeIterator<T> {
    boolean hasNext();
    T next();
}

// ========== 具体树迭代器 ==========

/**
 * 前序遍历迭代器(根-左-右)
 * 使用栈实现非递归遍历
 */
class PreOrderIterator<T> implements TreeIterator<T> {
    private final Deque<TreeNode<T>> stack = new ArrayDeque<>();

    public PreOrderIterator(TreeNode<T> root) {
        if (root != null) {
            stack.push(root);
        }
    }

    @Override
    public boolean hasNext() {
        return !stack.isEmpty();
    }

    @Override
    public T next() {
        if (!hasNext()) {
            throw new NoSuchElementException("遍历结束");
        }
        TreeNode<T> node = stack.pop();
        // 右子节点先入栈(后访问),左子节点后入栈(先访问)
        if (node.right != null) stack.push(node.right);
        if (node.left != null) stack.push(node.left);
        return node.data;
    }
}

/**
 * 中序遍历迭代器(左-根-右)
 */
class InOrderIterator<T> implements TreeIterator<T> {
    private final Deque<TreeNode<T>> stack = new ArrayDeque<>();
    private TreeNode<T> current;

    public InOrderIterator(TreeNode<T> root) {
        this.current = root;
    }

    @Override
    public boolean hasNext() {
        return current != null || !stack.isEmpty();
    }

    @Override
    public T next() {
        while (current != null) {
            stack.push(current);
            current = current.left;
        }
        TreeNode<T> node = stack.pop();
        current = node.right;
        return node.data;
    }
}

/**
 * 后序遍历迭代器(左-右-根)
 * 使用双栈实现
 */
class PostOrderIterator<T> implements TreeIterator<T> {
    private final Deque<T> result = new ArrayDeque<>();

    public PostOrderIterator(TreeNode<T> root) {
        if (root != null) {
            Deque<TreeNode<T>> stack1 = new ArrayDeque<>();
            Deque<TreeNode<T>> stack2 = new ArrayDeque<>();
            stack1.push(root);
            while (!stack1.isEmpty()) {
                TreeNode<T> node = stack1.pop();
                stack2.push(node);
                if (node.left != null) stack1.push(node.left);
                if (node.right != null) stack1.push(node.right);
            }
            while (!stack2.isEmpty()) {
                result.push(stack2.pop());
            }
        }
    }

    @Override
    public boolean hasNext() {
        return !result.isEmpty();
    }

    @Override
    public T next() {
        if (!hasNext()) {
            throw new NoSuchElementException("遍历结束");
        }
        return result.pop();
    }
}

/**
 * 层序遍历迭代器(广度优先,BFS)
 */
class LevelOrderIterator<T> implements TreeIterator<T> {
    private final Queue<TreeNode<T>> queue = new LinkedList<>();

    public LevelOrderIterator(TreeNode<T> root) {
        if (root != null) {
            queue.offer(root);
        }
    }

    @Override
    public boolean hasNext() {
        return !queue.isEmpty();
    }

    @Override
    public T next() {
        if (!hasNext()) {
            throw new NoSuchElementException("遍历结束");
        }
        TreeNode<T> node = queue.poll();
        if (node.left != null) queue.offer(node.left);
        if (node.right != null) queue.offer(node.right);
        return node.data;
    }
}

// ========== 客户端代码 ==========

public class BinaryTreeIteratorDemo {
    /**
     * 辅助方法:使用迭代器打印遍历结果
     */
    private static <T> void printTraversal(String name, TreeIterator<T> iterator) {
        System.out.print(name + ": ");
        List<T> result = new ArrayList<>();
        while (iterator.hasNext()) {
            result.add(iterator.next());
        }
        System.out.println(result);
    }

    public static void main(String[] args) {
        /*
         * 构建二叉树:
         *         1
         *        / \
         *       2   3
         *      / \   \
         *     4   5   6
         *    /   / \
         *   7   8   9
         */
        TreeNode<Integer> root = new TreeNode<>(1,
            new TreeNode<>(2,
                new TreeNode<>(4,
                    new TreeNode<>(7), null),
                new TreeNode<>(5,
                    new TreeNode<>(8),
                    new TreeNode<>(9))),
            new TreeNode<>(3,
                null,
                new TreeNode<>(6)));

        System.out.println("===== 二叉树遍历 =====");
        printTraversal("前序遍历(根-左-右)", new PreOrderIterator<>(root));
        printTraversal("中序遍历(左-根-右)", new InOrderIterator<>(root));
        printTraversal("后序遍历(左-右-根)", new PostOrderIterator<>(root));
        printTraversal("层序遍历(广度优先)", new LevelOrderIterator<>(root));

        // 筛选偶数节点
        System.out.println("\n===== 筛选偶数节点 =====");
        TreeIterator<Integer> allNodes = new PreOrderIterator<>(root);
        System.out.print("偶数节点: ");
        while (allNodes.hasNext()) {
            Integer value = allNodes.next();
            if (value % 2 == 0) {
                System.out.print(value + " ");
            }
        }
        System.out.println();
    }
}

六、UML 类图 ​

┌─────────────────┐
│     Client       │
└────────┬────────┘
         │ 调用迭代器
         ▼
┌─────────────────┐         ┌─────────────────┐
│ Iterator (接口)  │◀────────│ Aggregate (接口) │
│ +hasNext()      │ create  │ +createIterator()│
│ +next()         │────────▶└────────┬────────┘
│ +remove()       │                  │ 实现
└────────┬────────┘         ┌────────┴────────┐
         │ 实现              │                 │
┌────────┴────────┐  ┌──────┴─────┐  ┌───────┴──────┐
│ConcreteIterator │  │Concrete    │  │Concrete      │
│ +hasNext()      │  │Aggregate A │  │Aggregate B   │
│ +next()         │  │+createIter()│  │+createIter() │
└─────────────────┘  └────────────┘  └──────────────┘

七、Java 8 Stream API 中的迭代器思想 ​

java
import java.util.*;
import java.util.stream.*;

/**
 * 现代 Java 中,Stream API 提供了更强大的迭代能力
 */
public class StreamIteratorDemo {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("张三", 20, 85.5),
            new Student("李四", 22, 92.0),
            new Student("王五", 19, 78.0),
            new Student("赵六", 21, 95.5),
            new Student("孙七", 23, 88.0)
        );

        // Stream 本质上也是一种迭代的抽象
        System.out.println("===== Stream 遍历 =====");
        students.stream()
                .filter(s -> s.getScore() >= 85.0)
                .sorted(Comparator.comparing(Student::getScore).reversed())
                .map(s -> s.getName() + ": " + s.getScore())
                .forEach(System.out::println);

        // Collectors 收集结果
        Map<String, Double> scoreMap = students.stream()
                .collect(Collectors.toMap(Student::getName, Student::getScore));
        System.out.println("\n分数映射: " + scoreMap);

        // reduce 聚合
        double avgScore = students.stream()
                .mapToDouble(Student::getScore)
                .average()
                .orElse(0.0);
        System.out.println("平均分: " + avgScore);
    }
}

八、优缺点分析 ​

优点 ​

  1. 简化集合遍历:为不同的集合提供统一的遍历接口
  2. 单一职责:遍历行为从集合中分离,各自职责清晰
  3. 支持多种遍历方式:同一集合可以有不同的迭代器(正序、倒序、过滤等)
  4. 隐藏内部结构:客户端不需要了解集合的底层实现
  5. 支持并发遍历:多个迭代器可以同时遍历同一个集合

缺点 ​

  1. 增加类数量:每个集合都需要对应的迭代器类
  2. 对于简单集合:如果集合很简单,直接使用 for 循环更简洁
  3. 修改集合困难:如果集合的内部结构改变,迭代器也需要相应修改

九、使用场景 ​

  • Java 集合框架:ArrayList、HashMap、TreeSet 等都实现了 Iterator
  • 自定义集合:为自定义数据结构提供迭代能力
  • 树形结构遍历:二叉树、B树、红黑树的遍历
  • 图遍历:图的深度优先和广度优先遍历
  • 数据库结果集:JDBC ResultSet 就是一种迭代器
  • 分页查询:每次返回一部分数据,类似懒加载迭代器

十、最佳实践 ​

  1. 遵循 Java 的 Iterator 和 Iterable 接口:让自定义集合支持 for-each
  2. 考虑线程安全:如果集合在遍历中可能被修改,使用并发安全的迭代器
  3. 提供多种迭代器:为集合提供正序、倒序、过滤等多种迭代方式
  4. 不要在遍历中修改集合:除非使用迭代器的 remove 方法,否则会抛出 ConcurrentModificationException
  5. 使用 try-with-resources:对于需要关闭资源的迭代器
java
// 推荐:使用 Iterable 接口
class MyCollection<T> implements Iterable<T> {
    private final List<T> data = new ArrayList<>();

    @Override
    public Iterator<T> iterator() {
        return data.iterator();
    }

    // 这样就可以使用 for-each 了
    // for (T item : myCollection) { ... }
}

总结:迭代器模式为遍历集合提供了一种统一的方式,隐藏了集合的内部结构。Java 集合框架中的 Iterator 和 Iterable 接口就是迭代器模式的经典实现。在实际开发中,除了使用标准的 Iterator,还可以自定义迭代器来支持特殊的遍历需求(如树的遍历、过滤遍历等)。