1. 为什么需要迭代器模式
在软件开发中,我们经常需要处理各种集合数据。想象你正在开发一个音乐播放器应用,里面可能有以下几种集合:
- 播放列表(线性列表)
- 歌曲分类(树形结构)
- 最近播放记录(栈结构)
- 好友分享的歌曲(图结构)
如果每次遍历这些集合时,都需要了解它们的具体实现方式,代码会变得非常混乱。比如要遍历树形结构的分类,你可能需要写递归代码;而遍历线性列表时,又需要写for循环。这就是迭代器模式要解决的问题。
关键点:迭代器模式的核心价值在于将集合的存储结构与遍历行为解耦,让客户端可以用统一的方式访问各种集合。
2. 迭代器模式的核心结构
2.1 基本组件
迭代器模式主要包含四个关键角色:
- Iterator接口:
java复制public interface Iterator<T> {
boolean hasNext();
T next();
void remove(); // 可选
}
- ConcreteIterator实现:
java复制public class PlaylistIterator implements Iterator<Song> {
private List<Song> songs;
private int position = 0;
public PlaylistIterator(List<Song> songs) {
this.songs = songs;
}
@Override
public boolean hasNext() {
return position < songs.size();
}
@Override
public Song next() {
return songs.get(position++);
}
}
- Collection接口:
java复制public interface Playlist {
Iterator<Song> createIterator();
void addSong(Song song);
}
- ConcreteCollection实现:
java复制public class DefaultPlaylist implements Playlist {
private List<Song> songs = new ArrayList<>();
@Override
public Iterator<Song> createIterator() {
return new PlaylistIterator(songs);
}
@Override
public void addSong(Song song) {
songs.add(song);
}
}
2.2 模式关系图
code复制[Client] --> [Collection]
[Client] --> [Iterator]
[Collection] <|-- [ConcreteCollection]
[Iterator] <|-- [ConcreteIterator]
[ConcreteCollection] --> [ConcreteIterator]
3. 迭代器模式的五种典型实现方式
3.1 内部类实现
最经典的做法是在集合类内部实现迭代器:
java复制public class TreeCollection implements Collection {
// 树结构的实现...
private class TreeIterator implements Iterator {
// 可以访问外部类的私有成员
public boolean hasNext() { ... }
public Object next() { ... }
}
public Iterator iterator() {
return new TreeIterator();
}
}
3.2 外部迭代器
迭代器作为独立类存在:
java复制public class FileSystemIterator implements Iterator {
private File[] files;
private int index;
public FileSystemIterator(String path) {
this.files = new File(path).listFiles();
}
// 实现接口方法...
}
3.3 泛型迭代器
Java风格的泛型实现:
java复制public interface Iterable<T> {
Iterator<T> iterator();
}
public class GenericCollection<T> implements Iterable<T> {
private T[] elements;
// 其他实现...
}
3.4 惰性迭代器
特别适合大数据集合的遍历:
java复制public class DatabaseIterator implements Iterator {
private ResultSet rs;
private boolean hasNext;
public DatabaseIterator(ResultSet rs) {
this.rs = rs;
advance();
}
private void advance() {
try {
hasNext = rs.next();
} catch (SQLException e) {
hasNext = false;
}
}
// 实现接口方法...
}
3.5 过滤迭代器
实现条件过滤功能:
java复制public class FilteringIterator implements Iterator {
private Iterator source;
private Predicate predicate;
private Object nextItem;
public FilteringIterator(Iterator source, Predicate predicate) {
this.source = source;
this.predicate = predicate;
advance();
}
private void advance() {
while (source.hasNext()) {
Object item = source.next();
if (predicate.test(item)) {
nextItem = item;
return;
}
}
nextItem = null;
}
// 实现接口方法...
}
4. 迭代器模式在真实项目中的应用
4.1 Java集合框架
Java的Collection框架是迭代器模式的最佳示例:
java复制List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
// 使用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
// 增强for循环底层也是迭代器
for (String s : list) {
System.out.println(s);
}
4.2 文件系统遍历
实现跨平台的文件遍历:
java复制public class FileSystem implements Iterable<File> {
private File root;
public FileSystem(String rootPath) {
this.root = new File(rootPath);
}
@Override
public Iterator<File> iterator() {
return new FileIterator(root);
}
private static class FileIterator implements Iterator<File> {
private Stack<File> stack = new Stack<>();
public FileIterator(File root) {
stack.push(root);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public File next() {
File current = stack.pop();
if (current.isDirectory()) {
for (File child : current.listFiles()) {
stack.push(child);
}
}
return current;
}
}
}
4.3 数据库查询结果
处理大量数据库记录:
java复制public class QueryResult implements Iterable<Map<String, Object>> {
private ResultSet rs;
public QueryResult(ResultSet rs) {
this.rs = rs;
}
@Override
public Iterator<Map<String, Object>> iterator() {
return new ResultSetIterator(rs);
}
private static class ResultSetIterator implements Iterator<Map<String, Object>> {
private ResultSet rs;
private boolean hasNext;
public ResultSetIterator(ResultSet rs) {
this.rs = rs;
advance();
}
private void advance() {
try {
hasNext = rs.next();
} catch (SQLException e) {
hasNext = false;
}
}
@Override
public boolean hasNext() {
return hasNext;
}
@Override
public Map<String, Object> next() {
try {
Map<String, Object> row = new HashMap<>();
ResultSetMetaData meta = rs.getMetaData();
for (int i = 1; i <= meta.getColumnCount(); i++) {
row.put(meta.getColumnName(i), rs.getObject(i));
}
advance();
return row;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
4.4 复合对象遍历
处理树形结构数据:
java复制public class TreeNode implements Iterable<TreeNode> {
private String name;
private List<TreeNode> children = new ArrayList<>();
public TreeNode(String name) {
this.name = name;
}
public void addChild(TreeNode child) {
children.add(child);
}
@Override
public Iterator<TreeNode> iterator() {
return new DepthFirstIterator(this);
}
private static class DepthFirstIterator implements Iterator<TreeNode> {
private Stack<TreeNode> stack = new Stack<>();
public DepthFirstIterator(TreeNode root) {
stack.push(root);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public TreeNode next() {
TreeNode current = stack.pop();
for (int i = current.children.size() - 1; i >= 0; i--) {
stack.push(current.children.get(i));
}
return current;
}
}
}
5. 迭代器模式的进阶技巧
5.1 并发修改检测
实现fail-fast机制:
java复制public class SafeArrayList<T> implements Iterable<T> {
private List<T> list = new ArrayList<>();
private int modCount = 0;
public void add(T item) {
list.add(item);
modCount++;
}
@Override
public Iterator<T> iterator() {
return new SafeIterator();
}
private class SafeIterator implements Iterator<T> {
private int expectedModCount = modCount;
private int index = 0;
@Override
public boolean hasNext() {
checkModification();
return index < list.size();
}
@Override
public T next() {
checkModification();
return list.get(index++);
}
private void checkModification() {
if (expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
}
}
}
5.2 并行迭代
多线程安全迭代:
java复制public class ParallelIterator<T> implements Iterator<T> {
private final List<T> list;
private final AtomicInteger index;
public ParallelIterator(List<T> list) {
this.list = list;
this.index = new AtomicInteger(0);
}
@Override
public boolean hasNext() {
return index.get() < list.size();
}
@Override
public T next() {
int i = index.getAndIncrement();
if (i >= list.size()) {
throw new NoSuchElementException();
}
return list.get(i);
}
}
5.3 记忆迭代器
记住遍历位置:
java复制public class BookmarkIterator<T> implements Iterator<T> {
private final List<T> list;
private int position;
private final String bookmark;
public BookmarkIterator(List<T> list, String bookmark) {
this.list = list;
this.bookmark = bookmark;
this.position = loadPosition(bookmark);
}
private int loadPosition(String bookmark) {
// 从存储加载上次的位置
return 0; // 简化实现
}
@Override
public boolean hasNext() {
return position < list.size();
}
@Override
public T next() {
T item = list.get(position++);
savePosition();
return item;
}
private void savePosition() {
// 保存当前位置到存储
}
}
5.4 反向迭代
从后向前遍历:
java复制public class ReverseList<T> implements Iterable<T> {
private final List<T> list;
public ReverseList(List<T> list) {
this.list = list;
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private int index = list.size() - 1;
@Override
public boolean hasNext() {
return index >= 0;
}
@Override
public T next() {
return list.get(index--);
}
};
}
}
6. 迭代器模式的最佳实践
6.1 何时使用迭代器模式
适合使用迭代器模式的场景:
- 需要统一遍历不同类型的集合
- 需要支持多种遍历算法
- 需要隐藏集合的内部实现
- 需要支持并行遍历
- 集合结构可能经常变化
6.2 实现注意事项
-
接口设计:
- 保持迭代器接口最小化
- 考虑添加
remove()方法支持删除 - Java 8以后可以考虑支持
forEachRemaining()
-
性能考量:
- 对于随机访问集合,直接索引可能更快
- 对于链表等结构,迭代器是必须的
- 考虑缓存常用操作结果
-
线程安全:
- 明确文档说明迭代器的线程安全保证
- 要么实现fail-fast机制
- 要么实现线程安全迭代器
-
资源管理:
- 迭代器可能持有资源(如数据库连接)
- 考虑实现
AutoCloseable接口 - 文档中明确说明资源释放责任
6.3 常见陷阱
-
并发修改问题:
- 在迭代过程中修改集合会导致未定义行为
- 要么实现fail-fast机制
- 要么使用并发集合
-
多次迭代问题:
- 某些迭代器只能使用一次
- 文档中应明确说明
-
资源泄漏:
- 迭代器可能持有资源
- 确保正确关闭
-
性能陷阱:
- 某些迭代器的
hasNext()和next()可能有不同性能特征 - 避免在循环中频繁调用
hasNext()
- 某些迭代器的
7. 迭代器模式与其他模式的关系
7.1 与组合模式
迭代器模式常用来遍历组合模式构建的树形结构:
java复制public class CompositeIterator implements Iterator<Component> {
private Stack<Iterator<Component>> stack = new Stack<>();
public CompositeIterator(Iterator<Component> iterator) {
stack.push(iterator);
}
@Override
public boolean hasNext() {
if (stack.isEmpty()) return false;
Iterator<Component> iterator = stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
}
return true;
}
@Override
public Component next() {
Iterator<Component> iterator = stack.peek();
Component component = iterator.next();
if (component instanceof Composite) {
stack.push(component.iterator());
}
return component;
}
}
7.2 与工厂方法模式
集合通常使用工厂方法创建迭代器:
java复制public abstract class Collection {
public abstract Iterator createIterator();
// 其他方法...
}
7.3 与访问者模式
结合使用可以分离算法与数据结构:
java复制public void traverse(Visitor visitor) {
Iterator it = createIterator();
while (it.hasNext()) {
Object element = it.next();
element.accept(visitor);
}
}
7.4 与备忘录模式
保存和恢复迭代状态:
java复制public class IterationState {
private int position;
// 其他状态...
// getters and setters
}
public class RestorableIterator implements Iterator {
private List<?> list;
private int position;
public IterationState saveState() {
IterationState state = new IterationState();
state.setPosition(position);
return state;
}
public void restoreState(IterationState state) {
this.position = state.getPosition();
}
// 其他实现...
}
8. 现代编程语言中的迭代器
8.1 Java的增强
Java 8引入的流式操作:
java复制List<String> list = Arrays.asList("a", "b", "c");
list.stream()
.filter(s -> s.startsWith("a"))
.map(String::toUpperCase)
.forEach(System.out::println);
8.2 C#的yield
简化迭代器创建:
csharp复制public IEnumerable<int> GetNumbers() {
yield return 1;
yield return 2;
yield return 3;
}
8.3 Python的生成器
内存高效的迭代:
python复制def countdown(n):
while n > 0:
yield n
n -= 1
for x in countdown(5):
print(x)
8.4 JavaScript的迭代协议
ES6引入的迭代协议:
javascript复制const iterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step <= 3) {
return { value: step, done: false };
}
return { value: undefined, done: true };
}
};
}
};
for (const value of iterable) {
console.log(value);
}
9. 性能考量与优化
9.1 迭代器创建开销
每次调用iterator()都可能创建新对象。对于性能敏感场景,可以考虑:
- 重用迭代器对象(需重置状态)
- 使用静态迭代器(不适合并发)
- 提供轻量级迭代器变体
9.2 内联优化
现代JVM会对简单迭代器进行内联优化。保持迭代器实现简单有助于JIT优化:
java复制// 简单迭代器更可能被内联
@Override
public boolean hasNext() {
return index < array.length;
}
@Override
public T next() {
return array[index++];
}
9.3 批量操作
对于大数据集,考虑支持批量获取:
java复制public interface BatchIterator<T> extends Iterator<T> {
List<T> nextBatch(int size);
}
9.4 延迟初始化
对于计算代价高的迭代器:
java复制public class LazyIterator implements Iterator {
private boolean initialized = false;
private Iterator realIterator;
private void init() {
if (!initialized) {
realIterator = createRealIterator();
initialized = true;
}
}
@Override
public boolean hasNext() {
init();
return realIterator.hasNext();
}
// 其他方法...
}
10. 测试迭代器实现
10.1 单元测试要点
测试迭代器时应考虑:
- 空集合的迭代
- 单元素集合
- 多元素集合
- 并发修改检测
- 多次调用hasNext()
- 在末尾调用next()
- remove()操作(如果支持)
10.2 测试示例
java复制@Test
public void testEmptyCollection() {
Collection<String> empty = new EmptyCollection<>();
Iterator<String> it = empty.iterator();
assertFalse(it.hasNext());
assertThrows(NoSuchElementException.class, it::next);
}
@Test
public void testConcurrentModification() {
List<String> list = new ArrayList<>(Arrays.asList("a", "b"));
Iterator<String> it = list.iterator();
list.add("c");
assertThrows(ConcurrentModificationException.class, it::next);
}
@Test
public void testMultipleHasNext() {
List<String> list = Arrays.asList("a");
Iterator<String> it = list.iterator();
assertTrue(it.hasNext());
assertTrue(it.hasNext()); // 多次调用不应影响结果
assertEquals("a", it.next());
assertFalse(it.hasNext());
}
10.3 性能测试
测量迭代器在不同场景下的性能:
java复制@Benchmark
public void testArrayListIteration(Blackhole bh) {
List<Integer> list = arrayList; // JMH注入
for (Integer i : list) {
bh.consume(i);
}
}
@Benchmark
public void testLinkedListIteration(Blackhole bh) {
List<Integer> list = linkedList; // JMH注入
for (Integer i : list) {
bh.consume(i);
}
}
11. 实际项目经验分享
11.1 数据库结果集处理
在处理大型数据库结果集时,我发现以下模式特别有用:
java复制public class StreamingResultIterator implements Iterator<Record>, Closeable {
private final ResultSet rs;
private boolean hasNext;
public StreamingResultIterator(ResultSet rs) {
this.rs = rs;
advance();
}
private void advance() {
try {
hasNext = rs.next();
if (!hasNext) {
close();
}
} catch (SQLException e) {
close();
throw new RuntimeException(e);
}
}
@Override
public boolean hasNext() {
return hasNext;
}
@Override
public Record next() {
try {
Record record = convert(rs);
advance();
return record;
} catch (SQLException e) {
close();
throw new RuntimeException(e);
}
}
@Override
public void close() {
try {
rs.close();
} catch (SQLException e) {
// 记录日志
}
}
}
关键点:
- 及时关闭资源
- 提前获取hasNext状态
- 统一的异常处理
11.2 树形结构遍历
处理文件系统或组织架构时,我常用这种模式:
java复制public class DepthFirstIterator implements Iterator<Node> {
private final Deque<Iterator<Node>> stack = new ArrayDeque<>();
public DepthFirstIterator(Node root) {
stack.push(Collections.singletonList(root).iterator());
}
@Override
public boolean hasNext() {
while (!stack.isEmpty()) {
if (stack.peek().hasNext()) {
return true;
}
stack.pop();
}
return false;
}
@Override
public Node next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Node next = stack.peek().next();
if (!next.getChildren().isEmpty()) {
stack.push(next.getChildren().iterator());
}
return next;
}
}
经验:
- 使用栈而非递归避免栈溢出
- 惰性求值提高性能
- 支持中断遍历
11.3 多源合并迭代器
合并多个数据源时:
java复制public class MergingIterator<T extends Comparable<T>> implements Iterator<T> {
private final PriorityQueue<PeekingIterator<T>> queue;
@SafeVarargs
public MergingIterator(Iterator<T>... iterators) {
this.queue = new PriorityQueue<>(Comparator.comparing(PeekingIterator::peek));
for (Iterator<T> it : iterators) {
if (it.hasNext()) {
queue.add(new PeekingIterator<>(it));
}
}
}
@Override
public boolean hasNext() {
return !queue.isEmpty();
}
@Override
public T next() {
PeekingIterator<T> nextIt = queue.poll();
T next = nextIt.next();
if (nextIt.hasNext()) {
queue.offer(nextIt);
}
return next;
}
}
private static class PeekingIterator<T> implements Iterator<T> {
private final Iterator<T> delegate;
private T peeked;
public PeekingIterator(Iterator<T> delegate) {
this.delegate = delegate;
advance();
}
public T peek() {
return peeked;
}
@Override
public boolean hasNext() {
return peeked != null;
}
@Override
public T next() {
T next = peeked;
advance();
return next;
}
private void advance() {
peeked = delegate.hasNext() ? delegate.next() : null;
}
}
使用场景:
- 合并多个排序结果
- 多路归并排序
- 分布式数据聚合
12. 迭代器模式的未来演进
12.1 响应式流
现代响应式编程中的迭代器演进:
java复制Flux<String> flux = Flux.fromIterable(Arrays.asList("foo", "bar"));
flux.subscribe(System.out::println);
特点:
- 支持背压
- 异步处理
- 更丰富的操作符
12.2 协程与生成器
Kotlin的协程实现:
kotlin复制fun sequence() = sequence {
yield(1)
yieldAll(listOf(2, 3))
}
fun main() {
sequence().forEach { println(it) }
}
优势:
- 更简洁的语法
- 更好的性能
- 支持挂起和恢复
12.3 流式处理
Java的Stream API演进:
java复制List<String> list = Arrays.asList("a", "b", "c");
list.parallelStream()
.filter(s -> s.startsWith("a"))
.map(String::toUpperCase)
.forEach(System.out::println);
发展方向:
- 更强大的聚合操作
- 更好的并行支持
- 与数据库更深度集成
12.4 跨语言迭代协议
如WebAssembly的迭代器支持:
wat复制(module
(type $iterator (func (result i32)))
(table $iterators 1 anyfunc)
(elem (i32.const 0) $next)
(func $next (type $iterator) (result i32)
;; 实现迭代逻辑
)
(export "next" (func $next))
)
