Java 8列表与stream映射

我有一个List<Item>集合。 我需要将其转换为Map<Integer, Item>地图的关键字必须是集合中项目的索引。 我不知道如何做到这一点与stream。 就像是:

 items.stream().collect(Collectors.toMap(...)); 

任何帮助?

由于这个问题被认为是可能的重复我需要补充一点,我的具体问题是 – 如何获得列表中的项目的位置,并把它作为一个关键的价值

您可以使用IntStream创build索引Stream ,然后将其转换为Map

 Map<Integer,Item> map = IntStream.range(0,items.size()) .boxed() .collect(Collectors.toMap (i -> i, i -> items.get(i))); 

为了完整性,另一个解决scheme是使用自定义收集器:

 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()); 

这个解决scheme是并行友好的,不依赖于源(你可以使用没有随机访问的列表或Files.lines()或其他)。

不要觉得你必须在stream中做任何事情 。 我只会做:

 AtomicInteger index = new AtomicInteger(); items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i)); 

只要你不平行stream,这将工作,它避免了可能昂贵和/或问题(在重复的情况下) get()indexOf()操作。

(你不能使用一个常规的intvariables来代替AtomicInteger因为从lambdaexpression式外部使用的variables必须是有效的final请注意,当无争议(在这种情况下), AtomicInteger速度非常快,不会造成性能问题。但是,如果您担心,您可以使用非线程安全计数器。)

这是更新的答案,并没有在评论中提到的问题。

 Map<Integer,Item> outputMap = IntStream.range(0,inputList.size()).boxed().collect(Collectors.toMap(Function.identity(), i->inputList.get(i))); 

使用第三方库( protonpack例如,但也有其他),你可以用它的索引zip值,瞧:

 StreamUtils.zipWithIndex(items.stream()) .collect(Collectors.toMap(Indexed::getIndex, Indexed::getValue)); 

虽然getIndex返回一个long ,所以你可能需要使用类似于下面的东西来施放它:

 i -> Integer.valueOf((int) i.getIndex()) 

Eran的答案通常是随机访问列表的最佳方法。

如果您的List不是随机访问,或者您有一个Stream而不是List ,则可以使用forEachOrdered

 Stream<Item> stream = ... ; Map<Integer, Item> map = new HashMap<>(); AtomicInteger index = new AtomicInteger(); stream.forEachOrdered(item -> map.put(index.getAndIncrement(), item)); 

这是安全的,如果stream是平行的,即使目的地图是线程不安全的并且作为副作用被操作。 forEachOrdered保证项目按顺序一次处理。 由于这个原因,并行运行速度不太可能会提高。 (如果在forEachOrdered之前在stream水线中有昂贵的操作,那么可能会有一些加速。)