Java Iterator(迭代器)(超详细)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
在 Java 开发中,集合框架(Collection Framework)是处理数据的核心工具之一。无论是存储订单信息、用户列表还是配置参数,开发者都需要通过高效的方式遍历这些数据。Java Iterator(迭代器) 作为集合框架的重要组成部分,提供了一种统一且安全的遍历机制。本文将从基础概念、核心方法、实际应用到常见误区,逐步解析迭代器的原理与使用技巧,帮助读者在编程实践中灵活运用这一工具。
一、迭代器:集合遍历的“导航员”
1.1 什么是迭代器?
迭代器(Iterator) 是 Java 中用于遍历集合(如 List
、Set
等)的接口,它提供了一种“向前移动”的方式,允许开发者逐个访问集合中的元素,而无需直接暴露集合的内部结构。
形象比喻:
将集合比作一本厚重的书籍,迭代器就像是一支“荧光笔”,逐页标记需要阅读的内容,而不会让读者直接翻动书页的内页结构。
1.2 为什么需要迭代器?
传统 for
循环虽然能遍历数组,但面对动态变化的集合(如 ArrayList
或 HashSet
)时存在以下问题:
- 依赖索引:无法直接遍历无序的
Set
; - 安全性:直接修改集合内容可能导致
ConcurrentModificationException
异常。
迭代器的设计解决了这些问题,通过封装遍历逻辑和提供安全删除功能,成为集合遍历的标准方案。
二、迭代器的核心方法与使用流程
2.1 获取迭代器实例
要使用迭代器,需通过集合对象调用 iterator()
方法:
List<String> orders = new ArrayList<>(Arrays.asList("Order1", "Order2"));
Iterator<String> iterator = orders.iterator();
注意:迭代器的泛型需与集合元素类型一致。
2.2 核心方法详解
迭代器的核心方法包括 hasNext()
和 next()
:
boolean hasNext()
:检查是否还有下一个元素。E next()
:获取下一个元素,若无元素则抛出NoSuchElementException
。
示例代码
while (iterator.hasNext()) {
String order = iterator.next();
System.out.println("Processing: " + order);
}
2.3 安全删除元素:remove()
方法
迭代器提供 remove()
方法,可在遍历时安全删除元素,避免 ConcurrentModificationException
:
while (iterator.hasNext()) {
String order = iterator.next();
if (order.equals("Order2")) {
iterator.remove(); // 安全删除当前元素
}
}
注意:
- 不能在
foreach
或普通for
循环中直接调用remove()
; - 每次
next()
后才能调用remove()
,否则抛出异常。
三、迭代器的典型应用场景
3.1 过滤与处理数据
在订单管理系统中,迭代器可用于筛选特定条件的订单:
List<Order> orders = ...;
Iterator<Order> iterator = orders.iterator();
while (iterator.hasNext()) {
Order order = iterator.next();
if (order.getStatus().equals("CANCELLED")) {
iterator.remove(); // 删除已取消的订单
} else {
updateOrderStatus(order); // 更新订单状态
}
}
3.2 遍历不可变集合
若集合不允许直接修改,可通过迭代器只读访问:
List<String> readOnlyList = Collections.unmodifiableList(orders);
Iterator<String> safeIterator = readOnlyList.iterator();
// 可遍历但无法调用 remove()
四、迭代器与增强型 for 循环的对比
4.1 增强型 for 循环的局限性
Java 的增强型 for
循环(如 for (String order : orders)
)简洁易用,但存在两个限制:
- 无法删除元素:循环内部调用
orders.remove(order)
会抛出异常; - 不支持多集合操作:无法同时遍历多个集合。
4.2 迭代器的优势
- 支持安全删除:通过
iterator.remove()
实现; - 统一接口:可遍历所有
Iterable
类型的集合(如List
、Set
、Map.entrySet()
等)。
4.3 代码对比
// 增强型 for 循环(不可删除)
for (String order : orders) {
if (order.equals("Order2")) {
// 无法在此处直接删除
}
}
// 迭代器方式(可删除)
Iterator<String> it = orders.iterator();
while (it.hasNext()) {
String order = it.next();
if (order.equals("Order2")) {
it.remove(); // 安全删除
}
}
五、常见问题与进阶技巧
5.1 “ConcurrentModificationException” 异常
当多线程或外部修改集合时,迭代器会抛出此异常。解决方案包括:
- 使用
CopyOnWriteArrayList
等线程安全的集合; - 在遍历前复制集合(
new ArrayList<>(original)
)。
5.2 迭代器的“状态”特性
迭代器遍历是单向的,且状态会随 next()
调用改变。例如:
Iterator<String> it = orders.iterator();
it.next(); // 移动到第一个元素
it.next(); // 移动到第二个元素
// 此时无法返回第一个元素
5.3 泛型与类型安全
迭代器的泛型需与集合元素类型匹配,否则需强制转换(不推荐):
Iterator iterator = orders.iterator(); // 未指定泛型
Object element = iterator.next(); // 需自行处理类型
六、高级场景:自定义迭代器
6.1 实现自定义集合的迭代器
若需为自定义集合(如 MyList
)提供迭代器,需实现 Iterable
接口并返回 Iterator
:
public class MyList<T> implements Iterable<T> {
private Node<T> head;
@Override
public Iterator<T> iterator() {
return new MyIterator<>(this);
}
// 内部类 MyIterator 实现 Iterator 方法
}
6.2 遍历 Map 的键值对
通过 Map.entrySet()
结合迭代器访问键值对:
Map<String, Integer> orderCounts = new HashMap<>();
Iterator<Map.Entry<String, Integer>> entries = orderCounts.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, Integer> entry = entries.next();
System.out.println(entry.getKey() + ": " + entry.getValue());
}
结论
Java Iterator(迭代器) 是集合框架中不可或缺的工具,它通过封装遍历逻辑、提供安全删除功能,帮助开发者高效且安全地操作动态数据。无论是基础的订单处理,还是复杂的多线程场景,掌握迭代器的使用方法和原理,都能显著提升代码的健壮性和可维护性。
本文通过代码示例、场景分析和常见问题解答,系统性地展示了迭代器的核心知识点。建议读者在实际开发中多加练习,逐步内化其使用模式,从而在 Java 开发中更加得心应手。