8.6 Java 8列表与流进行映射?| Java Debug 笔记

104 阅读1分钟

本文正在参加「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速度非常快,不会造成性能问题。 但是如果您担心,可以使用非线程安全的计数器。)