Java Collectors.toMap(): 将Stream收集到Map

后端 潘老师 6个月前 (10-30) 155 ℃ (0) 扫码查看

学习如何将Stream转换为Map,即使用Collectors.toMap()和Collectors.groupingBy()方法将Stream的项收集到Map中。

1.注意IllegalStateException

请注意,首先我们要知道Stream元素是否具有转Map后键字段的相同的情况,如果有的话,并且我们使用Collectors.toMap()方法,代码将抛出IllegalStateException。类似如下:

Exception in thread “main” java.lang.IllegalStateException:
Duplicate key 3 (attempted merging values Item[id=3, name=Item3] and Item[id=3, name=Item3])
at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:135)

2.将Stream转换为Map(无重复键)

在这种情况下,我们必须确保Stream中的每个键都是唯一的。处理完成后,我们将获得Map<K,V>,其中指定的键K仅与单个值V相关联。
为了演示目的,我们使用包含3个项目的Stream:

Stream<Item> stream = Stream.of(
  new Item(1, "Item1"),
  new Item(2, "Item2"),
  new Item(3, "Item3")
);

我们可以将上述Item实例的Stream转换为两种方式的Map<Long, String>:

  • Map键- Item ID
    Map值- Item Name。
Map<Long, String> mapWithValue = stream.collect(Collectors.toMap(Item::id, Item::name));
// {1=Item1, 2=Item2, 3=Item3}

在下一个示例中,我们使用Function.identity()将对象本身作为Map值来转换为Map<Long, Item>。

Map<Long, Item> map = stream.collect(Collectors.toMap(Item::id, Function.identity()));
// {1=Item[id=1, name=Item1], 2=Item[id=2, name=Item2], 3=Item[id=3, name=Item3]}

3. 将Stream转换为Map(有重复键)

如果流中有重复键的元素,有两种可能的方法来处理它:

  • 将所有值收集到List中并将它们与键关联起来
  • 仅选择一个值,并丢弃同一键的所有其他值

为了演示目的,我们使用包含五个元素的Stream,其中三个项目具有重复键’3’。

Stream<Item> streamWithDuplicates = Stream.of(
  new Item(1, "Item1"),
  new Item(2, "Item2"),
  new Item(3, "Item3-1"),
  new Item(3, "Item3-2"),
  new Item(3, "Item3-3")
);

3.1将Stream收集到Map的List中

如果我们想将所有键的值存储在List中,我们可以使用Collectors.groupingBy()来收集元素,形成Map<key, List>的格式。在下面的示例中,我们将项目收集到Map的List中,即Map<K, List<Item>>。

Map<Long, List<Item>> mapWithList = streamWithDuplicates.collect(Collectors.groupingBy(Item::id));

程序输出:

{
    1=[Item[id=1, name=Item1]],
    2=[Item[id=2, name=Item2]],
    3=[
            Item[id=3, name=Item3-1],
            Item[id=3, name=Item3-2],
            Item[id=3, name=Item3-3]
        ]
}

我们可以将该Stream转换为List包含Item名称的Map,即Map<K, List<String>>。

Map<Long, List<String>> mapWithGroupedValues = streamWithDuplicates
    .collect(
        Collectors.groupingBy(Item::id,
        Collectors.mapping(Item::name, Collectors.toList())));

程序输出:

{
    1=[Item1],
    2=[Item2],
    3=[Item3-1, Item3-2, Item3-3]
}

3.2. 将Stream收集到Map中并丢弃重复值

另一种方法是仅从多个值中选择一个值,并丢弃相同键的其他值。

在我们的示例中,我们可能决定选择Map键的最新名称,即item3-3,并丢弃其他值,即item3-1和item3-2。

以下代码使用第三个参数mergeFunction,当遇到键上的冲突值时,它选择必须与键关联的值。

Map<Long, Item> mapWithGrouping = streamWithDuplicates
    .collect(Collectors.toMap(Item::id, Function.identity(), (oldValue, newValue) -> newValue));

程序输出:

{
    1=Item[id=1, name=Item1],
    2=Item[id=2, name=Item2],
    3=Item[id=3, name=Item3-3]
}

4.维持插入顺序或按键排序

有时,我们可能希望维护将键值对插入Map时的顺序。 LinkedHashMap维护这样的插入顺序,因此我们可以使用它来收集Stream项。

LinkedHashMap<Long, String> mapWithValueInInsertionOrder = stream
    .collect(Collectors.toMap(
        Item::id,
        Item::name,
        (o, n) -> n,
        LinkedHashMap::new));

同样,如果我们想应用并维护Map键的排序顺序,我们可以使用TreeMap。

TreeMap<Long, String> mapwithSortedKeys = stream
    .collect(Collectors.toMap(
        Item::id,
        Item::name,
        (o, n) -> n,
        TreeMap::new));

5. 结论

本Java Stream教程讨论了将stream项收集到Map或List的多种方法。 我们看到了每种方法的示例及其输出,以便更好地了解每种方法对stream项的作用。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/back/10497.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】