要让业务实体类原生支持for-each循环,必须实现Iterable<T>接口并重写iterator()方法返回合法Iterator;泛型T需匹配遍历元素类型,iterator()须每次返回新实例,避免状态污染与并发问题。

要让业务实体类原生支持 for-each 循环,核心是实现 Iterable<T> 接口,并重写 iterator() 方法返回一个符合逻辑的 Iterator<T>。这不是“加个注解就能用”的功能,而是需要明确迭代意图:你希望 for-each 遍历的是对象的哪些数据?是内部集合?是字段组合?还是某种计算序列?下面从实战角度分步说明。
明确迭代目标再决定 Iterable 的泛型类型
泛型参数 T 必须与你希望 for-each 拿到的元素类型一致。常见场景有:
- 若遍历的是订单里的商品列表 →
implements Iterable<Product> - 若遍历的是用户信息的字段名和值对 →
implements Iterable<Map.Entry<String, Object>> - 若遍历的是订单总金额拆分成“100元”、“50元”、“20元”等面额 →
implements Iterable<Integer>
错误做法:声明为 Iterable<Order> 却在 iterator() 中返回单个订单实例——这会导致 for-each 每次拿到整个对象,失去遍历意义。
iterator() 方法必须返回真正可遍历的 Iterator 实例
不能直接 return null 或抛异常,也不能返回仅支持一次遍历的临时对象(除非设计如此)。推荐方式:
-
委托给内部集合:如订单类持有
List<Item> items,则return items.iterator(); -
封装自定义 Iterator:需单独定义内部类或匿名类,正确实现
hasNext()和next(),并注意remove()可选但建议抛UnsupportedOperationException -
使用 Stream + Spliterators(Java 8+):适合只读、惰性、不可变场景,例如
return items.stream().iterator();
示例(委托方式):
<pre>public class Order implements Iterable<Item> {private final List<Item> items = new ArrayList<>();
@Override
public Iterator<Item> iterator() {
return items.iterator(); // 直接复用,安全且高效
}
>
避免常见陷阱:状态污染与并发问题
多个 for-each 同时执行时,若共享同一个 Iterator 实例,会相互干扰。因此:
-
每次调用
iterator()必须返回新实例,不能缓存或复用已有 Iterator 对象 - 若内部数据可能被多线程修改,而迭代器未做同步,for-each 过程中可能抛
ConcurrentModificationException。此时应考虑使用线程安全集合(如CopyOnWriteArrayList),或在iterator()中返回快照(如new ArrayList<>(items).iterator()) - 不要在
next()中修改被迭代的底层结构(如边遍历边删元素),除非你明确实现了 fail-fast 之外的语义
配合增强 for 循环写出更自然的业务代码
一旦实现正确,业务层调用就非常简洁:
<pre>Order order = new Order();order.addItem(new Item("苹果", 5.5));
order.addItem(new Item("香蕉", 3.2));
// 原生支持 for-each
for (Item item : order) {
System.out.println(item.getName() + ": ¥" + item.getPrice());
}
>
甚至可链式使用 Stream 操作:order.stream().filter(i -> i.getPrice() > 4).map(Item::getName).collect(Collectors.toList()) —— 因为 Iterable 是 StreamSupport.stream() 的天然输入源。

















