Terminal operation either returns one value (of the same or another type than the input type) or does not return anything at all (produces only side effects). It does not allow another operation to be applied afterward and closes the stream.
In this post, we will continue covering the last of the terminal operations called collect():
R collect(Collector<T,A,R> collector)
It is a specialization of the reduce() operation. It allows implementing a vast variety of algorithms using the ready-to-use collectors from the java.util.stream.Collectors class. We discussed how to create a custom collector in Java streams 25. Collect 1. Custom collector. In this article, we will use only the collectors produced by the Collectors class.
Creating Map object using Collectors.mapping() collector
The Collectors.mapping() collector transforms each stream element according to the specified function and then collects the results using the specified collector:
— Collector<T,?,R> mapping(Function<T,U> mapper, Collector<U,A,R> downstream) – returns a Collector which maps each element of type T to a value of type U and then accumulates the U values using the downstream reduction.
The downstream is a collector that collects U values into a structure of type R.
Before demonstrating the Collectors.mapping() collector usage, let us review how the map() operation works. For example:
List<Character> list = Stream.of("cat", "fish", "cat", "dog")
.map(s -> s.charAt(0)).collect(Collectors.toList());
System.out.print(list); //prints: [c, f, c, d]
As you can see, we have mapped each stream element to the first character only and then accumulated the results in a List. The same result can be achieved using Collectors.mapping() collector:
List<Character> list = Stream.of("cat", "fish", "cat", "dog")
.collect(Collectors.mapping(s -> s.charAt(0),
Collectors.toList()));
System.out.print(list); //prints: [c, f, c, d]
The following is another example of the Collectors.mapping() collector usage:
Set<Integer> set = Stream.of("cat", "fish", "cat", "dog")
.collect(Collectors.mapping(String::length,
Collectors.toSet()));
System.out.print(sset); //prints: [3, 4]
These examples do not justify the Collectors.mapping() collector usage.
But let us say we would like to reduce the stream to a Map that has element length as a key and the List of the first characters as a value like this: Stream.of(“cat”, “fish”, “cat”, “dog”) => {3=[c, c, d], 4=[f]}
To do it using map() or any of the operations we have discussed already is not possible, because we need to map each element to two values (length and the first character) at the same time. That is where the Collectors.mapping() collector shines:
Map<Integer, List<Character>> map =
Stream.of("cat", "fish", "cat", "dog")
.collect(Collectors.groupingBy(String::length,
Collectors.mapping(s -> s.charAt(0),
Collectors.toList())));
System.out.print(map); //prints: {3=[c, c, d], 4=[f]}
That is what the Collectors.mapping() collector does: it applies to each stream element the specified mapping and accumulates the results at the same time.
Similarly, the Collectors.mapping() collector can be used with the Collectors.partitioningBy() collector:
Map<Boolean, List<Character>> map =
Stream.of("cat", "fish", "cat", "dog")
.collect(Collectors.partitioningBy(s -> s.length() == 3,
Collectors.mapping(s -> s.charAt(0),
Collectors.toList())));
System.out.print(map); //prints: {false=[f], true=[c, c, d]}
In the next post, we will talk about creating a Map object using Collectors.flatMapping() collector (typically used as a parameter for Collectors.groupingBy() or Collectors.partitioningBy() collector).
See other posts on Java 8 streams and posts on other topics.
You can also use navigation pages for Java stream related blogs:
— Java 8 streams blog titles
— Create stream
— Stream operations
— Stream operation collect()
The source code of all the code examples is here in GitHub.
Send your comments using the link Contact or in response to my newsletter.
If you do not receive the newsletter, subscribe via link Subscribe under Contact.