本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看<活动链接>
提问:Java 8列表与流如何进行映射
我有一个List<Item>集合。 我需要将其转换为Map <Integer,Item>映射的键必须是集合中该项的索引。 我不知道如何使用流来做到这一点。 就像是:
items.stream().collect(Collectors.toMap(...));
有什么能帮助我吗?
由于此问题被确定为可能重复,因此我需要补充一点,我的具体问题是-如何获取项目在列表中的位置并将其作为键值
回答1:
您可以使用IntStream创建索引流,然后将它们转换为Map:
Map<Integer,Item> map =
IntStream.range(0,items.size())
.boxed()
.collect(Collectors.toMap (i -> i, i -> items.get(i)));
回答2:
为了完整起见,另一种解决方案是使用自己设置的Collector:
public static <T> Collector<T, ?, Map<Integer, T>> toMap() {
return Collector.of(HashMap::new, (map, t) -> map.put(map.size(), t),
(m1, m2) -> {
int s = m1.size();
m2.forEach((k, v) -> m1.put(k+s, v));
return m1;
});
}
使用方法如下:
Map<Integer, Item> map = items.stream().collect(toMap());
该解决方案是支持并发操作的,并且不依赖于源(您可以使用列表,而无需随机访问Files.lines()或进行任何其他操作)。
回答3:
不必觉得您必须在流中/与流一起做所有事情。 我会如此实现:
AtomicInteger index = new AtomicInteger();
items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i));
只要您不并行化流,它就可以正常工作,并且可以避免get()和indexOf()操作的潜在开销和/或问题(在重复的情况下)。
(您不能使用常规的int变量来代替AtomicInteger,因为从lambda表达式外部使用的变量必须有效地是最终变量。请注意,在无争议的情况下(如本例所示),AtomicInteger速度非常快,不会造成性能问题。 但是如果您担心,可以使用非线程安全的计数器。)