关键在于框架只依赖Iterator接口本身,不感知数据源类型或结构;所有遍历组件入参统一为Iterator<T>,封装方式包括数据库分页、文件逐行读取和树形结构遍历,支持remove()及扩展MutableIterator,推荐forEachRemaining简化纯消费操作。

在编写通用框架时,用 Iterator 接口解耦数据源与遍历算法,关键不是“怎么拿到 Iterator”,而是“让框架只依赖 Iterator 接口本身,完全不感知数据源类型或结构”。这样,无论底层是内存列表、数据库游标、文件流、网络分页响应,还是自定义树形结构,只要它能提供 Iterator,框架就能无缝处理。
把 Iterator 当作唯一输入契约
框架中所有遍历相关组件(如处理器、过滤器、聚合器)的入参统一声明为 Iterator<T>,而非 List<T>、Stream<T> 或具体实现类。这强制上游负责适配,下游专注逻辑:
- 避免在框架内写
if (obj instanceof List)或collection.stream()这类绑定实现的代码 - 不调用
size()、get(i)、toArray()等集合特有方法 - 所有循环严格遵循
while (it.hasNext()) { T item = it.next(); ... }模式
封装数据源为 Iterator 的三种典型方式
不同数据源需各自实现“如何生成 Iterator”,但对框架而言,它们最终都只是 Iterator<Record>:
-
数据库分页结果:包装 JDBC
ResultSet,每次next()触发一次rs.next()并映射为对象;翻页逻辑藏在hasNext()内部(如缓存下一页数据或按需查询) -
大文件逐行读取:用
BufferedReader包装,hasNext()判断是否还有行,next()调用readLine()并解析 -
树形结构遍历:实现一个内部栈或队列的迭代器,将深度优先(DFS)或广度优先(BFS)逻辑封装在
next()中,对外仍呈现线性 Iterator 接口
支持安全修改与状态隔离
如果框架需要在遍历时修改数据源(如跳过脏数据、标记已处理项),应依赖 Iterator 自带的 remove() 方法,而不是回调原始集合:
立即学习“Java免费学习笔记(深入)”;
- 确保传入的 Iterator 实现了
remove()(例如ArrayList.iterator()支持,但Arrays.asList().iterator()不支持) - 若需更复杂操作(如插入、更新),可定义扩展接口
MutableIterator<T>继承自Iterator<T>,保持向后兼容 - 避免多线程共享同一 Iterator 实例;每次遍历应获取新实例,保证状态隔离
配合 Java 8+ 的 forEachRemaining 提升简洁性
对于纯消费型操作(如日志记录、异步提交),直接使用 iterator.forEachRemaining(item -> {...}),比手写 while 循环更简洁,且由 JDK 保证行为一致:
- 该方法内部仍基于
hasNext()/next(),语义清晰无歧义 - 适合框架中提供默认遍历行为的工具方法(如
DrainUtils.drain(iterator, sink)) - 不适用于需要条件中断或中间状态判断的场景(此时仍需显式 while 控制)
不复杂但容易忽略:真正解耦的标志,是你能把框架 JAR 包单独拿出来,不带任何集合实现类,仅靠 java.util.Iterator 就能编译通过并运行核心流程。


















