在 Java 8 中从 Stream 惯用地创建多值 Map
Idiomatically creating a multi-value Map from a Stream in Java 8
有什么方法可以使用 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<? super K,? super V,? extends V>>)
:
填充多值 Map<K, Collection<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;
}));
有没有更简洁的方式来做到这一点,例如通过在一条语句中初始化和填充地图?
如果用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());
有什么方法可以使用 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<? super K,? super V,? extends V>>)
:
Map<K, Collection<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;
}));
有没有更简洁的方式来做到这一点,例如通过在一条语句中初始化和填充地图?
如果用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());