1. 当书架遇上图书管理员:初识迭代器
小时候我最喜欢去图书馆借书,但总是会遇到这样的困惑:面对一排排的书架,怎么才能高效找到想要的书?直到我发现每个书架都配有专门的图书管理员,他们负责把读者需要的书依次找出来——这像极了编程世界中的迭代器模式。
在Java世界里,集合就像装满了书的书架,而迭代器就是那位专业的图书管理员。他不需要我们知道书架的具体结构(是数组还是链表),只需按顺序把书递到我们手中。这种"藏结构于幕后,显遍历于前台"的设计哲学,正是迭代器模式的精髓。
2. 模式架构:拆解迭代器组成部件
2.1 设计图鉴
迭代器模式的"配方"包含两个核心原料:
- Iterator接口:定义标准操作(hasNext、next)
- Aggregate接口:负责生产专属迭代器
就像不同的书架(数组/链表)需要配置不同寻书方式的图书管理员,每个集合都应该生产与之匹配的迭代器。这种解耦设计让集合的遍历方式完全独立于集合本身的结构。
3. Java实践:手写两套迭代方案
开发环境:Java 17 + IntelliJ IDEA
3.1 内置迭代器基础用法
List<String> coffeeList = Arrays.asList("美式", "拿铁", "摩卡", "卡布奇诺");
// 获取专用咖啡师(迭代器)
Iterator<String> barista = coffeeList.iterator();
while(barista.hasNext()) {
String coffee = barista.next();
System.out.println("正在冲泡:" + coffee);
// 特殊处理:遇到摩卡需要加巧克力粉
if("摩卡".equals(coffee)) {
System.out.println(">>> 撒上法芙娜巧克力粉");
}
}
3.2 自定义温度过滤器迭代器
假设我们需要筛选60度以上的饮品:
// 定制温度检测迭代器(仅Java示例)
class TemperatureFilterIterator implements Iterator<Drink> {
private final Iterator<Drink> originIterator;
private Drink nextDrink;
public TemperatureFilterIterator(List<Drink> drinks) {
this.originIterator = drinks.iterator();
prefetchValidDrink();
}
private void prefetchValidDrink() {
while(originIterator.hasNext()) {
Drink candidate = originIterator.next();
if(candidate.getTemperature() >= 60) {
nextDrink = candidate;
return;
}
}
nextDrink = null;
}
@Override
public boolean hasNext() {
return nextDrink != null;
}
@Override
public Drink next() {
Drink current = nextDrink;
prefetchValidDrink(); // 预取下一杯合格饮品
return current;
}
}
// 使用示例
List<Drink> menu = Arrays.asList(
new Drink("热牛奶", 70),
new Drink("冰美式", 5),
new Drink("热拿铁", 65)
);
Iterator<Drink> thermometer = new TemperatureFilterIterator(menu);
while(thermometer.hasNext()) {
System.out.println("适宜冬季饮品:" + thermometer.next().getName());
}
4. 模式深潜:关联技术揭秘
4.1 泛型加持的通用迭代器
通过泛型技术可以让迭代器具备更强的普适性:
public interface SmartIterator<T> {
boolean hasNext();
T next();
default void remove() {
throw new UnsupportedOperationException();
}
}
// 具体实现类继承时指定泛型类型
class CircularIterator<T> implements SmartIterator<T> {
// 实现环形遍历逻辑...
}
4.2 组合模式中的迭代器应用
当处理树形结构时,迭代器可以结合组合模式:
public class Department implements Iterable<Employee> {
private List<Employee> staff = new ArrayList<>();
@Override
public Iterator<Employee> iterator() {
return new CompositeIterator(staff.iterator());
}
// 实现深度优先遍历的内部类
private class CompositeIterator implements Iterator<Employee> {
// 具体的递归遍历实现...
}
}
5. 现实战场:迭代器的典型应用场景
5.1 分页读取利器
数据库查询结果的分批处理非常适合迭代器模式:
public class PagingIterator implements Iterator<List<Record>> {
private int currentPage = 0;
private final int pageSize;
public PagingIterator(int pageSize) {
this.pageSize = pageSize;
}
@Override
public boolean hasNext() {
return Database.hasMoreRecords(currentPage * pageSize);
}
@Override
public List<Record> next() {
List<Record> batch = Database.fetchRecords(currentPage++, pageSize);
return batch;
}
}
5.2 敏感词过滤器
社交媒体平台常用迭代器进行内容审查:
public class ContentScanner {
public void scanContent(Iterator<String> contentIterator) {
while(contentIterator.hasNext()) {
String segment = contentIterator.next();
if(SensitiveWordLibrary.contains(segment)) {
System.out.println("发现敏感词:" + segment);
contentIterator.remove(); // 支持移除操作
}
}
}
}
6. 权衡之选:模式优劣全景分析
优势维度:
- 遍历操作与集合实现完全解耦
- 支持多种遍历策略的灵活切换
- 简化客户端调用复杂度
- 遵守单一职责原则
短板领域:
- 迭代器与集合状态不同步时容易抛出ConcurrentModificationException
- 部分实现会带来额外内存消耗
- 复杂迭代器会增加代码维护成本
7. 避坑指南:开发者必知注意事项
- 版本一致原则:确保迭代器工作时集合结构不被外部修改
- 资源及时释放:针对文件流等资源的迭代器需要实现AutoCloseable
- 异常处理机制:在next()调用前必须验证hasNext()
- 遍历终止策略:实现可中断的迭代逻辑
- 反向遍历支持:必要时可扩展previous()方法
8. 模式演进:迭代器的现代发展
随着Java Stream API的普及,迭代器正与函数式编程深度融合:
// 传统迭代器改造为Spliterator
public class SensorDataSpliterator implements Spliterator<DataPoint> {
// 实现分片遍历逻辑...
}
// 与Stream API整合使用
StreamSupport.stream(new SensorDataSpliterator(), false)
.filter(dp -> dp.getValue() > 100)
.forEach(System.out::println);
9. 总结
从基础遍历到智能迭代,Java迭代器模式就像一位经验丰富的导游,带领我们在复杂的数据集合中从容穿行。在微服务架构盛行的今天,掌握自定义迭代器的实现技巧,能够显著提升系统的灵活性和可维护性。当您下次需要处理非标数据集时,不妨尝试打造专属的迭代器,让遍历操作既优雅又高效。