2017-08-08 2 views
0

Y a-t-il un moyen d'initialiser et de remplir élégamment une valeur multiple Map<K,Collection<V>> en utilisant l'API de flux de Java 8?Création idiomatique d'une carte à valeurs multiples à partir d'un flux en Java 8

Je sais qu'il est possible de créer une seule valeur Map<K, V> en utilisant les fonctionnalités Collectors.toMap(..):

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

Malheureusement, cette méthode ne fonctionne pas bien pour les clés éventuellement non uniques, telles que le nom d'une personne.

D'autre part, il est possible de remplir une valeur multiple Map<K, Collection<V>> utilisant 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; 
})); 

est-il pas un moyen plus concis de le faire, par exemple en initialisant et en remplissant la carte dans une déclaration?

+3

est-ce pas un usage manuel cas pour groupingBy? –

+0

@PatrickParker Oui, vous et Holger avez raison. Je n'ai jamais beaucoup utilisé cette méthode. – errantlinguist

+0

@Patrick Parker: oui, c'est un cas d'utilisation parfait pour 'groupingBy', qui [est une application pratique de' computeIfAbsent'] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk /openjdk/8u40-b25/java/util/stream/Collectors.java#908). Bien sûr, du côté de l'application, 'groupingBy' est préférable. – Holger

Répondre

5

Si vous utilisez forEach, il est beaucoup plus simple à utiliser computeIfAbsent au lieu de compute:

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

Cependant, lorsque vous utilisez l'API Stream, il est préférable d'utiliser collect. Dans ce cas, utilisez groupingBy au lieu de toMap:

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