You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以惯用方式将Collection<Foo>映射为MultiMap<A,B>并一行返回新实例?

嘿,这个问题我太熟了!你提到的用Stream循环调用put的方式确实能解决问题,但确实有更优雅的实现,而且完全可以一行代码生成包含映射关系的全新Multimap实例,主要看你是否愿意用第三方库——首推Guava,它对Multimap的支持简直是量身定做的。

优雅实现方案(一行代码搞定)

首选:用Guava的Multimaps收集器

Guava专门提供了Multimaps.toMultimap()收集器,完美适配你的需求,一行代码就能生成全新的Multimap实例:

Multimap<A, B> resultMultimap = fooCollection.stream()
    .collect(Multimaps.toMultimap(Foo::getA, Foo::getB, HashMultimap::create));

这里的三个参数分别是:

  • Foo::getA:从每个Foo对象中提取作为键的A类型值
  • Foo::getB:提取对应键的B类型值
  • HashMultimap::create:指定要创建的Multimap实现(你也可以换成TreeMultimap::create或者其他Guava提供的Multimap类型,按需选择)

这种写法完全符合函数式编程风格,不需要手动初始化Multimap再填充,一步到位得到目标实例。

不用Guava?试试Java原生Collectors(稍繁琐但可行)

如果不想引入Guava依赖,用Java原生Stream API结合Collectors.groupingBy也能实现,不过默认会得到Map<A, List<B>>,如果要转成Multimap(比如Apache Commons Collections的ArrayListMultimap),可以这么写:

Multimap<A, B> resultMultimap = fooCollection.stream()
    .collect(Collectors.groupingBy(Foo::getA, Collectors.mapping(Foo::getB, Collectors.toList())))
    .entrySet().stream()
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, ArrayListMultimap::create));

不过这个写法相比Guava的方案就啰嗦不少,除非有严格的依赖限制,否则还是更推荐Guava的实现。

对比你原来的写法

你之前想到的循环填充方式:

Multimap<A, B> multimap = HashMultimap.create();
fooCollection.forEach(foo -> multimap.put(foo.getA(), foo.getB()));

这个写法逻辑清晰、容易理解,完全没有问题,但用收集器的写法更贴合Stream的设计理念,代码也更紧凑,尤其是能直接在一行内完成实例创建和数据映射。

内容的提问来源于stack exchange,提问作者Andrew Cheong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:27:58