【问题标题】:Idiomatically creating a multi-value Map from a Stream in Java 8惯用地从 Java 8 中的流创建多值映射
【发布时间】:2017-08-08 11:48:47
【问题描述】:

有没有办法使用 Java 8 的流 API 优雅地初始化和填充多值 Map<K,Collection<V>>

我知道可以使用 Collectors.toMap(..) 功能创建单值 Map<K, V>

Stream<Person> persons = fetchPersons();
Map<String, Person> personsByName = persons.collect(Collectors.toMap(Person::getName, Function.identity()));

很遗憾,该方法不适用于可能不唯一的键,例如人名。

另一方面,可以使用Map.compute(K, BiFunction&lt;? super K,? super V,? extends V&gt;&gt;) 填充多值Map&lt;K, Collection&lt;V&gt;&gt;

Stream<Person> persons = fetchPersons();
Map<String, Set<Person>> personsByName = new HashMap<>();
persons.forEach(person -> personsByName.compute(person.getName(), (name, oldValue) -> {
    Set<Person> result = (oldValue== null) ? new HashSet<>() : oldValue;
    result.add(person);
    return result;
}));

没有更简洁的方法可以做到这一点,例如通过在一个语句中初始化和填充地图?

【问题讨论】:

  • 这不是 groupingBy 的教科书用例吗?
  • @PatrickParker 是的,你和 Holger 是对的。我从来没有使用过这种方法。
  • @Patrick Parker:是的,这是groupingBy 的完美用例,is a practical application of computeIfAbsent。当然,在应用端,groupingBy 更可取。

标签: java dictionary java-stream multimap


【解决方案1】:

如果你使用forEach,使用computeIfAbsent而不是compute要简单得多:

Map<String, Set<Person>> personsByName = new HashMap<>();
persons.forEach(person ->
    personsByName.computeIfAbsent(person.getName(), key -> new HashSet<>()).add(person));

但是,在使用 Stream API 时,最好使用 collect。在这种情况下,请使用groupingBy 而不是toMap

Map<String, Set<Person>> personsByName =
    persons.collect(Collectors.groupingBy(Person::getName, Collectors.toSet());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    • 2023-03-15
    • 1970-01-01
    相关资源
    最近更新 更多