I played around with a solution using groupingBy
, mapping
and reducing
to the following question: Elegantly create map with object fields as key/value from object stream in Java 8. Summarized the goal was to get a map with age as key and the hobbies of a person as a Set
.
One of the solutions I came up with (not nice, but that's not the point) had a strange behaviour.
With the following list as input:
List<Person> personList = Arrays.asList(
new Person(/* name */ "A", /* age */ 23, /* hobbies */ asList("a")),
new Person("BC", 24, asList("b", "c")),
new Person("D", 23, asList("d")),
new Person("E", 23, asList("e"))
);
and the following solution:
Collector<List<String>, ?, Set<String>> listToSetReducer = Collectors.reducing(new HashSet<>(), HashSet::new, (strings, strings2) -> {
strings.addAll(strings2);
return strings;
});
Map<Integer, Set<String>> map = personList.stream()
.collect(Collectors.groupingBy(o -> o.age,
Collectors.mapping(o -> o.hobbies, listToSetReducer)));
System.out.println("map = " + map);
I got:
map = {23=[a, b, c, d, e], 24=[a, b, c, d, e]}
clearly not what I was expecting. I rather expected this:
map = {23=[a, d, e], 24=[b, c]}
Now if I just replace the order of (strings, strings2)
of the binary operator (of the reducing collector) to (strings2, strings)
I get the expected result. So what did I miss here?
Did I misinterpret the reducing
-collector? Or which documentation piece did I miss that makes it obvious that my usage was not working as expected?
Java version is 1.8.0_121 if that matters.