Java Reference
In-Depth Information
Collecting Data in Maps
You can collect data from a stream into a Map . The toMap() method of the Collectors class returns a collector to
collect data in a Map . The method is overloaded and it has three versions:
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U>
valueMapper)
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U>
valueMapper, BinaryOperator<U> mergeFunction)
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U>
valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)
The first version takes two arguments. Both arguments are a Function . The first argument maps the stream
elements to keys in the map. The second argument maps stream elements to values in the map. If duplicate
keys are found, an IllegalStateException is thrown. The following snippet of code collects a person's data in a
Map<long,String> whose keys are the person's ids and values are person's names:
Map<Long,String> idToNameMap = Person.persons()
.stream()
.collect(Collectors.toMap(Person::getId, Person::getName));
System.out.println(idToNameMap);
{1=Ken, 2=Jeff, 3=Donna, 4=Chris, 5=Laynie, 6=Li}
Suppose you want collect a person's name based on gender. Here is the first, incorrect attempt:
Map<Person.Gender,String> genderToNamesMap = Person.persons()
.stream()
.collect(Collectors.toMap(Person::getGender, Person::getName));
The code throws the following runtime exception. Only a partial output is shown.
Exception in thread "main" java.lang.IllegalStateException: Duplicate key Ken ...
The runtime is complaining about the duplicate keys because Person::getGender will return the gender of the
person as the key and you have many males and females.
The solution is to use the second version of the toMap() method to obtain the collection. It lets you specify a
merge function as a third argument. The merged function is passed the old and new values for the duplicate key.
The function is supposed to merge the two values and return a new value that will be used for the key. In your case,
you can concatenate the names of all males and females. The following snippet of code accomplishes this:
Map<Person.Gender,String> genderToNamesMap = Person.persons()
.stream()
.collect(Collectors.toMap(Person::getGender, Person::getName,
(oldValue, newValue) -> String.join(", ", oldValue, newValue)));
System.out.println(genderToNamesMap);
{FEMALE=Donna, Laynie, MALE=Ken, Jeff, Chris, Li}
 
Search WWH ::




Custom Search