I have a List of
Map<String, List<GroupUser>> groupUserList = users.stream()
You can get a
Map<String, List<String>> where the key is the group and the value is a list of names with:
Map<String, List<String>> groupUserList = users.stream() .collect( Collectors.groupingBy(GroupUser::getGroup, Collectors.mapping(GroupUser::getName, Collectors.toList())));
Looking at groupingBy javadocs we see that 1 of the overloads has the signature:
public static <T,K,A,D> Collector<T,?,Map<K,D>> groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)
You can think of this
downstream as a collector that tells the stream what to do with the elements that it separated by key (in our case the group is the key).
Notice that it is another collector. Next we want to transform a
GroupUser into a
String which is it's name. We know we transform elements of a stream with
map. However this takes a
Look further into the Collectors API we see that we already have a collector that maps elements and takes another
public static <T,U,A,R> Collector<T,?,R> mapping(Function<? super T,? extends U> mapper, Collector<? super U,A,R> downstream)
Now from the docs:
downstream - a collector which will accept mapped values. Since we mapped
GroupedUser to it's name the last thing left to do is to collect them in a list and that is one of the most commonly used collectors.
Bottom line: Simple usage of collectors tells you that this is where you finished the processing of your stream, however we can compose collectors in more complex scenarios like this one.