在Java 8中从流中以惯用方式创建多值Map [英] Idiomatically creating a multi-value Map from a Stream in Java 8

查看:801
本文介绍了在Java 8中从流中以惯用方式创建多值Map的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is there any way to elegantly initialize and populate a multi-value Map<K,Collection<V>> using Java 8's stream API?

我知道可以使用 Map< K,V> docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-rel =nofollow noreferrer> Collectors.toMap(..) 功能:

I know it's possible to create a single-value Map<K, V> using the Collectors.toMap(..) functionalities:

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

不幸的是,该方法不适用于可能非唯一的密钥,例如人名。

Unfortunately, that method won't work well for possibly non-unique keys such as a person's name.

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

On the other hand, it's possible to populate a multi-value Map<K, Collection<V>> using Map.compute(K, BiFunction<? super K,? super V,? extends V>>):

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

是否有更简洁的方法,例如通过在一个语句中初始化和填充地图?

Is there no more concise way of doing this, e.g. by initializing and populating the map in one statement?

推荐答案

如果你使用 forEach ,使用 computeIfAbsent 而不是 compute 更简单:

If you use forEach, it’s much simpler to use computeIfAbsent instead of 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

However, when using the Stream API, it’s preferable to use collect. In this case, use groupingBy instead of toMap:

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

这篇关于在Java 8中从流中以惯用方式创建多值Map的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆