Java 8 Stream收集后如何获取索引?映射时如何获取递增计数?
Java 8 Stream实现递增计数与获取索引的解决方案
嘿,我来帮你搞定这个Stream改写的问题!首先咱们先解决你最关心的在map操作里获取递增计数的问题,再聊聊怎么获取元素索引。
一、用Stream实现递增计数创建X对象
你原来的循环里,是过滤出a.get() == 1的元素,然后用递增的count创建X对象。但Stream是无状态的,普通的int变量没法直接在map里递增(因为需要是final或effectively final,而且并行流会有线程安全问题)。这里推荐用AtomicInteger来维护计数,它是线程安全的原子类,不管串行还是并行流都能保证计数正确。
代码示例如下:
import java.util.concurrent.atomic.AtomicInteger; // ... AtomicInteger count = new AtomicInteger(0); List<X> newList = someList.stream() .filter(a -> a.get() == 1) // 注意你之前写的是equals("red"),这里要和原循环的判断逻辑一致哦 .map(a -> new X(count.incrementAndGet())) // 每次过滤成功就自增计数并传入X的构造方法 .collect(Collectors.toList());
如果确定只会用串行流,也可以用一个int[]数组来绕开final限制(因为数组是引用类型,属于effectively final),但这种方式在并行流里会有线程安全问题,所以还是优先用AtomicInteger:
int[] count = {0}; List<X> newList = someList.stream() .filter(a -> a.get() == 1) .map(a -> new X(++count[0])) .collect(Collectors.toList());
二、Stream处理中/收集后获取索引
1. 流处理过程中获取原始索引
如果你需要获取元素在原列表中的索引,可以用IntStream.range生成索引范围,再和原列表的元素配对:
// 获取过滤后元素的原始索引和元素本身 List<Map.Entry<Integer, A>> indexedFilteredElements = IntStream.range(0, someList.size()) .filter(i -> someList.get(i).get() == 1) .mapToObj(i -> new AbstractMap.SimpleEntry<>(i, someList.get(i))) .collect(Collectors.toList()); // 或者同时生成递增计数和原始索引(假设X有对应的构造方法) AtomicInteger count = new AtomicInteger(0); List<X> newListWithIndex = IntStream.range(0, someList.size()) .filter(i -> someList.get(i).get() == 1) .mapToObj(i -> new X(count.incrementAndGet(), i)) .collect(Collectors.toList());
2. 收集后获取列表的索引
如果已经把Stream收集成了List,想要获取每个元素在新列表中的索引,直接遍历索引即可:
List<X> collectedList = ...; // 已经收集好的X列表 IntStream.range(0, collectedList.size()) .forEach(i -> { X x = collectedList.get(i); // 这里可以使用x和它的索引i做处理 System.out.printf("索引%d的元素:%s%n", i, x); });
最后提醒你一下:你之前写的filter(a -> a.get().equals("red"))和原循环的a.get() == 1逻辑不匹配,要注意a.get()的返回类型哦,如果是int就用== 1,如果是String才用equals("red"),别搞混啦~
内容的提问来源于stack exchange,提问作者CCC
相关产品推荐
相关产品推荐

