Java 8 - How to use Collectors.collectingAndThen Collector with examples
This tutorial explains how to use the predefined collector returned by
Where,
- 1st input parameter is
- 2nd input parameter is
- output is a Collector with finisherClick to Read tutorial on 4 components of Collectors incl. 'finisher'(return type) of type
Thus, when there is a scenario where the stream elements need to be collected and then the collected object needs to be transformed using a given rule\function, then using the collectingAndThen collector both these tasks of collection and transformation can be specified and executed together.
Example#1 of Collectors.collectingAndThen
Problem Description: Given a stream of employees, we want to -
OUTPUT of the above code
Explanation of the code
Example#2 of Collectors.collectingAndThen
Problem Description: Given a stream of employees, we want to -
(Note - The
OUTPUT of the above code
Explanation of the code
Collectors.collectingAndThen()
method with examples. It first explains the method definition and then shows collectingAndThen()
method's usage using two Java 8 code examples, along with detailed explanation of the code.
Definition of Collectors.collectingAndThen() method
Collectors.collectingAndThen()
method is defined with the following signature - public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)
- 1st input parameter is
downstream
which is an instance of a Collector<T,A,R>
i.e. the standard definitionClick to Read Tutorial explaining Basics of Java 8 Collectors of a collector. In other words, any collector can be used here.- 2nd input parameter is
finisher
which needs to be an instance of a FunctionClick to Read Tutorial on Function functional interfaces<R,RR>
functional interface. This function instance takes as input an object of type R
which is the output from downstream collector, and it returns an output of type RR
which is the final return type of collectingAndThen
collector as well.- output is a Collector with finisherClick to Read tutorial on 4 components of Collectors incl. 'finisher'(return type) of type
RR
.
How the Collectors.collectingAndThen() method works
CollectingAndThen()
method first collects the elements of type T
of Stream<T>
using the Collector<T,A,R>
passed to it as the first parameter. As a result of applying the collector, stream elements are collected into an object of type R
. Using the Function<R,RR>
instance passed as the second parameter, the collected object of type R
is then transformed to an object of type RR
. This object of type RR
is the final object/value returned by the collectingAndThen collector.- Find the employee with the maximum salary for which we want to use the maxBy collector.
- The output of the maxBy collector being an
Optional
value, we want to check whether a value is present and then print the max salaried employee's name.
Java 8 Code Example#1 for Collectors.collectingAndThen
package com.javabrahman.java8.collector;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import com.javabrahman.java8.Employee;
public class CollectingAndThenExample {
static List<Employee> employeeList
= Arrays.asList(new Employee("Tom Jones", 45, 15000.00),
new Employee("Tom Jones", 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) {
String maxSalaryEmp = employeeList.stream().collect(
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(Employee::getSalary)),
(Optional<Employee> emp)-> emp.isPresent() ? emp.get().getName() : "none") );
System.out.println("Max salaried employee's name: "+ maxSalaryEmp);
}
}
//Employee.java POJO class
package com.javabrahman.java8;
import java.text.DecimalFormat;
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;
}
//Standard setters and getters for name,age and salary go here
public String toString(){
DecimalFormat dformat = new DecimalFormat(".##");
return "Employee Name:"+this.name;
}
//Standard hashcode() & equals() implementations go here
}
Max salaried employee's name: Tom Jones
CollectingAndThenExample
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 pipelinedClick to Read Tutorial explaining Concept of Pipelines in Computing to the
collect()
terminal operationClick to Read Tutorial explaining intermediate & terminal Stream operations. - To the
collect()
method,Collector
returned byCollectors.collectingAndThen()
method is passed as a parameter. - collectingAndThen collector takes 2 parameters -
- Collectors.maxBy collector with the
Employee
’s salary passed as the sort key using method reference Click to Read Tutorial on Java 8's Method References - “Employee::getSalary
”. - Ternary operator which checks if the
Optional<Employee>
value returned by maxBy collector is present. If yes, it extracts and returns the employee name from theEmployee
object returned by maxBy collector. If no, it returns the string “none
”.
- Collectors.maxBy collector with the
- Output printed is as expected - the name of the employee with maximum salary - “
Tom Jones
” is printed.
- Find the average salary of all employees using averagingDouble collector.
- Print the average salary after formatting it using
DecimalFormat
.
(Note - The
Employee
class and employeeList
objects with their values remain the same as the previous code usage example and hence are not shown below for brevity.)Java 8 Code Example#2 - Collectors.collectingAndThen
public static void main(String[] args) {
System.out.println("Max salaried employee's name: " + maxSalaryEmp);
String avgSalary = employeeList.stream().collect(
Collectors.collectingAndThen(
Collectors.averagingDouble(Employee::getSalary),
averageSalary -> new DecimalFormat("'$'0.00").format(averageSalary)));
System.out.println("Average salary in $: " + avgSalary);
}
Average salary in $: $9800.00
- collectingAndThen collector takes 2 parameters -
Collectors.averagingDouble
collector with theEmployee
’s salary passed as the attribute to be averaged using method reference - “Employee::getSalary
”.Function<Double,String>
instance specified using a lambda expression -“averageSalary -> new DecimalFormat("'$'0.00").format(averageSalary))
” which specifies that the average salary returned by the averagingDouble collector is to be formatted usingDecimalFormat
with specified format - “'$'0.00
”.
- Output printed is as expected - properly formatted average salary of all employees - “
$9800.00
” is printed.
Java 8 Collectors' Tutorials on JavaBrahman
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
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