I played with the solution using groupingBy , mapping and reducing to the following question: Elegantly create a map with object fields as key / value from an object stream in Java 8 . The goal was to get a card with age as a key and a personβs hobby as a Set .
One of the solutions I came up with (not nice, but it's not) was weird behavior.
With the following input:
List<Person> personList = Arrays.asList( new Person( "A", 23, 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 expected. I rather expected this:
map = {23=[a, d, e], 24=[b, c]}
Now, if I just replaced the order (strings, strings2) binary operator (reduction collector) with (strings2, strings) , I get the expected result. So what did I miss here? Am I misinterpreting reducing collector? Or what part of the documentation did I skip that makes it obvious that my use is not working properly?
The Java version is 1.8.0_121, if that matters.