This tutorial explains how to use Java 8’s predefined collector returned by Collectors.mapping()
method with examples. It first explains the definition of the static mapping()
method, followed by a quick explanation of its working, and then shows how to use Collector returned by Collectors.mapping()
using two Java 8 code examples.
Collectors.mapping() method
Collectors.mapping()
method is defined with the following signature –
public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T,? extends U> mapper,Collector<? super U,A,R> downstream)
Where,
– 1st input parameter is mapper
an instance of FunctionClick to Read Tutorial on Function Functional Interface functional interface, which converts stream elements of type T
to type U
– 2nd input parameter is downstream
an instance of a standard collectorClick to Read Tutorial on Collector basics which collects elements of type U
in the result type R
– output is a Collector
which collects elements of type T
in the result type R
.
How the Collector returned by Collectors.mapping() method works
The collector returned by Collector.mapping()
method acts as an adapterClick to Read Tutorial on Adapter Design Pattern which allows a collector to accept a type T
, instead of the type for which it was built, i.e. U
. The collector works by applying a mapping function from T
to U
which is passed to the Collector.mapping()
method as the first parameter(refer collector method signature above for more context on type T
& U
).
So, when you have a Collector<U,A,R>
which can process elements of type U
, but you need instead a Collector<T,A,R>
, then you can use the mapping collector to adapt your Collector<U,A,R>
using a Function<T,U>
.
When mapping collector is used to collect elements of a Stream<T>
, it first maps/transforms/converts the stream elements of type T
to type U
using Function<T,U>
, and then collects them using Collector<U,A,R>
, in effect allowing your collector which accepts Stream<U>
to now work with(or adapt to) Stream<T>
.
To complete our understanding of how the mapping collector works, let us see couple of Java 8 code examples which show show to use the collector in code.
//MappingCollector.java package com.javabrahman.java8.collector; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; public class MappingCollector { static List<Employee> employeeList = Arrays.asList(new Employee("Tom Jones", 45, 15000.00), new Employee("Harry Andrews", 45, 7000.00), new Employee("Ethan Hardy", 65, 8000.00), new Employee("Nancy Smith", 22, 10000.00), new Employee("Deborah Sprightly", 29, 9000.00)); public static void main(String[] args) { List<String> employeeNames = employeeList .stream() .collect(Collectors.mapping(Employee::getName, Collectors.toList())); System.out.println("List of employee names:" + employeeNames); } } //Employee.java(POJO class) package com.javabrahman.java8.collector; public class Employee { private String name; private Integer age; private Double salary; public Employee(String name, Integer age, Double salary) { this.name = name; this.age = age; this.salary = salary; } //Setters and Getters for name, age & salary go here public String toString(){ return "Name: "+ this.name + " Age: "+ this.age; } //Standard implementations for overridden hashcode() & equals() goes here }
MappingCollector
class contains a static list ofEmployee
objects –employeeList
.- In the
main()
method a stream ofEmployee
objects is created usingList.stream()
method. - Stream of employees is then pipelined to the
collect()
terminal operationClick to Read Tutorial explaining intermediate & terminal Stream operations. - To the
collect()
method,Collector
returned byCollectors.mapping()
method is passed as a parameter. - Mapping collector is invoked with the first input parameter(mapper function) as “
Employee::getName
”, which is a method referenceClick to Read Tutorial on Java 8’s Method References, to theEmployee.getName()
method. For the second input parameter(downstream collector)– collector returned byCollectors.toList()
is passed. - Mapping collector then works in 2 steps. In the 1st step, it uses the mapper function to convert
Stream<Employee>
(stream of Employee objects) to an equivalentStream<String>
(stream of Employee names). In the 2nd step, the downstream collector is used to collect all employee names in aList<String>
instance. - Collected
List
is assigned to aList<String>
variable namedemployeeNames
, and printed. As expected, names of the 5 employees are printed as list content.
(Note – The Employee
class and employeeList
objects with their values remain the same as the previous code usage example and hence are not shown again in example 2 below for brevity.)
public static void main(String[] args) { Optional<Integer> maxAge = employeeList .stream() .collect(Collectors.mapping((Employee emp) -> emp.getAge(), Collectors.maxBy(Integer::compareTo))); System.out.println("Max Age: " + maxAge.get()); }
- The
Employee
objects in the stream are collected, with the inputs this time being method reference toEmployee
’sgetAge()
method(as mapper function), and Collectors.maxBy()Click to Read tutorial on maxBy()/minBy() collectors(as downstream collector) withInteger
’s natural comparison order being used as it’s comparatorClick to Read in-depth tutorial on Java 8 Comparators’s sorting logic. - Mapping collector then works in 2 steps. In the 1st step, it uses the mapper function to convert
Stream<Employee>
(stream ofEmployee
objects) to an equivalentStream<Integer>
(stream of employee ages). In the 2nd step, the downstream collector is used to find the maximum age of among all employees. - Value of maximum age determined is assigned to an
Optional<Integer>
variable namedmaxAge
, and printed. As expected, the maximum age is printed as65
.
Understanding Basics of Java 8 CollectorsClick to Read Tutorial explaining basics of Java 8 CollectorsCollectors.groupingBy()Click to Read Tutorial on Grouping with CollectorsCollectors.partitioningBy()Click to Read Partitioning using Collectors TutorialCollectors.counting()Click to Read Counting with Collectors Tutorial Collectors.maxBy()/minBy()Click to Read Tutorial on finding max/min with CollectorsCollectors.joining()Click to Read Tutorial on joining as a String using CollectorsCollectors.collectingAndThen()Click to Read Tutorial on collectingAndThen CollectorCollectors.averagingInt() /averagingLong() /averagingDouble()Click to Read Tutorial on Averaging CollectorCollectors.toCollection()Click to Read Tutorial on Collectors.toCollection CollectorCollectors.mapping()Click to Read Tutorial on Mapping Collector
