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
Optionalvalue, 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
CollectingAndThenExampleclass contains a static list ofEmployeeobjects -employeeList.- In the
main()method a stream ofEmployeeobjects 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,Collectorreturned 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 theEmployeeobject 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.averagingDoublecollector 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 usingDecimalFormatwith 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