习惯性地从 Java 8 中的流创建多值映射

2022-09-03 04:57:05

有没有办法使用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,? extendv>>)来填充多值: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;
}));

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


答案 1

如果您使用 ,则使用起来比:forEachcomputeIfAbsentcompute

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

但是,在使用流 API 时,最好使用 .在这种情况下,请使用 代替 :collectgroupingBytoMap

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

答案 2