迭代器模式(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);
}
}八、优缺点分析
优点
- 简化集合遍历:为不同的集合提供统一的遍历接口
- 单一职责:遍历行为从集合中分离,各自职责清晰
- 支持多种遍历方式:同一集合可以有不同的迭代器(正序、倒序、过滤等)
- 隐藏内部结构:客户端不需要了解集合的底层实现
- 支持并发遍历:多个迭代器可以同时遍历同一个集合
缺点
- 增加类数量:每个集合都需要对应的迭代器类
- 对于简单集合:如果集合很简单,直接使用 for 循环更简洁
- 修改集合困难:如果集合的内部结构改变,迭代器也需要相应修改
九、使用场景
- Java 集合框架:ArrayList、HashMap、TreeSet 等都实现了 Iterator
- 自定义集合:为自定义数据结构提供迭代能力
- 树形结构遍历:二叉树、B树、红黑树的遍历
- 图遍历:图的深度优先和广度优先遍历
- 数据库结果集:JDBC ResultSet 就是一种迭代器
- 分页查询:每次返回一部分数据,类似懒加载迭代器
十、最佳实践
- 遵循 Java 的 Iterator 和 Iterable 接口:让自定义集合支持 for-each
- 考虑线程安全:如果集合在遍历中可能被修改,使用并发安全的迭代器
- 提供多种迭代器:为集合提供正序、倒序、过滤等多种迭代方式
- 不要在遍历中修改集合:除非使用迭代器的 remove 方法,否则会抛出 ConcurrentModificationException
- 使用 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,还可以自定义迭代器来支持特殊的遍历需求(如树的遍历、过滤遍历等)。