如何使用foreach重写Java中基于索引的嵌套循环?
把基于索引的嵌套循环转成foreach风格的实现
没问题,我来帮你搞定这个转换!原代码的核心是遍历bList中所有i < j的元素对(每对元素只比较一次,不会出现反向重复),要转成foreach风格,我们可以借助ListIterator来跟踪当前遍历的位置,完美复刻原逻辑:
推荐实现:用ListIterator跟踪位置
这种方法完全匹配原索引循环的行为,而且不管集合中是否有重复元素都能正常工作:
ListIterator<Ball> outerIter = bList.listIterator(); while (outerIter.hasNext()) { Ball ballI = outerIter.next(); // 内层迭代器直接从外层迭代器的下一个位置开始遍历 ListIterator<Ball> innerIter = bList.listIterator(outerIter.nextIndex()); while (innerIter.hasNext()) { Ball ballJ = innerIter.next(); System.out.println(ballI); System.out.println(ballJ); } }
为什么这么写?
outerIter.nextIndex()会返回外层迭代器下一个要访问的元素索引,也就是当前ballI的索引+1,刚好对应原代码里j = i + 1的起始位置。- CopyOnWriteArrayList的迭代器是快照式的,遍历过程中即使集合被修改也不会抛出
ConcurrentModificationException,和原集合的特性保持一致。
备选方案:用Stream API(声明式风格)
如果你更倾向于Java 8+的声明式写法,也可以用IntStream生成索引,再结合forEach实现:
IntStream.range(0, bList.size()) .forEach(i -> { IntStream.range(i + 1, bList.size()) .forEach(j -> { System.out.println(bList.get(i)); System.out.println(bList.get(j)); }); });
这个写法本质还是依赖索引,但用lambda表达式替代了传统的for循环,代码更简洁。
注意事项
- 不要直接嵌套两层普通foreach(比如
for(Ball b1 : bList) { for(Ball b2 : bList) {...}}),这样会遍历所有元素对(包括i >= j的情况),和原逻辑不符。 - 如果集合中存在重复元素,用
bList.indexOf(ballI)来获取索引的方法会出错(因为indexOf返回第一个匹配元素的索引),所以优先用ListIterator的位置跟踪方式。
内容的提问来源于stack exchange,提问作者Nikita Kalugin
相关产品推荐
相关产品推荐

