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

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










