增强for-each循环遍历集合时本质调用iterator接口,需集合实现iterable;遍历时禁止直接调用集合remove(),应使用迭代器remove()或批量操作;可修改对象字段但不能修改集合结构。

增强 for-each 循环是 Java 开发中高频使用的遍历工具,但它的“简洁”背后藏着关键差异:对业务实体集合(如 List<order></order>、Set<user></user>)的遍历,**真实依赖 Iterator 接口运行机制**;而对数组则走索引路径。实战高效扫描的前提,是看清它在集合场景下的本质——不是语法装饰,而是编译器生成的、带状态和约束的迭代器调用链。
明确适用前提:集合必须实现 Iterable 接口
for-each 能用于 List、Set、Queue 等,是因为它们都实现了 Iterable<t></t>。你的自定义业务集合若想支持 for-each,也必须提供符合规范的 iterator() 方法:
- 该方法每次调用都返回一个全新迭代器实例(不能复用或返回 this)
- 迭代器内部需维护独立游标(如
cursor)、是否完成等状态 - 例如
ArrayList返回私有类Itr,它持数组引用并跟踪当前下标
实战中避免 ConcurrentModificationException 的关键操作
业务扫描常伴随条件过滤或清理逻辑(如“遍历订单列表,取消超时未支付的订单”),此时直接调用 list.remove() 会立即触发 ConcurrentModificationException——这不是并发问题,而是 fail-fast 机制在起作用。
- ✅ 正确做法:使用迭代器自身的
remove()方法
for (Iteratorit = orders.iterator(); it.hasNext(); ) {
Order o = it.next();
if (o.isTimeout()) it.remove(); // 安全删除 - ❌ 错误写法:
for (Order o : orders) { if (o.isTimeout()) orders.remove(o); }→ 必抛异常 - 替代方案:收集待处理 ID 或对象,循环结束后批量操作(如
orders.removeAll(toCancel))
理解“只读遍历”的边界与安全修改方式
for-each 提供的是元素引用(对象类型)或副本(基本类型),它本身不支持通过循环变量反向修改集合结构,但允许安全修改对象字段:
- ⚠️
for (Order o : orders) { o.setStatus("CANCELLED"); }→ 合法,改的是对象状态,非集合结构 - ⚠️
for (int x : intArray) { x = 99; }→ 无效,x 是副本,原数组不变 - ✅ 若需更新数组元素,必须用传统 for 循环配合索引:
for (int i = 0; i
字节码级真相:它真在调 Iterator,不是假语法糖
反编译 class 文件可验证:对 Collection 类型,javac 确实生成了 iterator()、hasNext()、next() 三步调用。这意味着:
- 每一次 for-each 都创建一个新 Iterator 实例(轻量但非零开销)
- 自定义
Iterable实现可完全控制遍历行为(如懒加载、分页包装、权限过滤) - 第三方集合(如 Guava 的
ImmutableList)或 Spring Data 的Page若实现Iterable,for-each 仍能无缝工作










