Issue
Given a Map<String, Person>
where Person has a String getName()
(etc) method on it, how can I turn the Map<String, Person>
into a Map<String, String>
where the String
is obtained from calling Person::getName()
?
Pre-Java 8 I'd use
Map<String, String> byNameMap = new HashMap<>();
for (Map.Entry<String, Person> person : people.entrySet()) {
byNameMap.put(person.getKey(), person.getValue().getName());
}
but I'd like to do it using streams and lambdas.
I can't see how to do this in a functional style: Map/HashMap don't implement Stream
.
people.entrySet()
returns a Set<Entry<String, Person>>
which I can stream over, but how can I add a new Entry<String, String>
to the destination map?
Solution
With Java 8 you can do:
Map<String, String> byNameMap = new HashMap<>();
people.forEach((k, v) -> byNameMap.put(k, v.getName());
Though you'd be better off using Guava's Maps.transformValues, which wraps the original Map
and does the conversion when you do the get
, meaning you only pay the conversion cost when you actually consume the value.
Using Guava would look like this:
Map<String, String> byNameMap = Maps.transformValues(people, Person::getName);
EDIT:
Following @Eelco's comment (and for completeness), the conversion to a map is better done with Collectors.toMap like this:
Map<String, String> byNameMap = people.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, (entry) -> entry.getValue().getName());
Answered By - Nick Holt
Answer Checked By - Willingham (JavaFixing Volunteer)