Java 8 Collect vs Reduce Example
Hello readers, this tutorial explains the concept of reducing and collecting in Streams and Collector’s API respectively.
1. Introduction
1.1 Stream’s reduce() Method
Let’s take a look at the Streams API’s reduce()
method and how it can be used to perform reduction operations on the streams of data.
1.1.1 What is ‘reducing’ in the context of Streams?
Reducing in the context of Java8 Streams refers to the process of combining all elements in the stream repeatedly to produce a single value which is returned as the result of the reduction operation. Given a stream of elements there could be various ways in which one can reduce (or combine) them to a single result value such as summation of all elements (for numeric types), finding the maximum element from among all the elements (based on the element’s comparison order), and similar operations for combining multiple elements into a single resultant value.
The primary requirement of any reduction operation’s logic is that it should use two operands for the operation which are:
- The collective value aggregated or derived from the elements encountered so far which will be of the same type as the type of elements in the stream
- The value which is encountered next to the unprocessed value in the stream
Due to this inherent nature of reduction, operations requiring two operands both of which are of the same type as the type of elements in the stream being processed. Stream API’s reduce()
method also uses a BinaryOperator
function for defining the reduction operation logic. Let us now take a look at how the Stream API’s reduce()
operation is defined and used.
Method Signature
T reduce(T identity, BinaryOperator<T> accumulator)
Where,
- The identity is the initial value of the type
T
which will be used as the first value in the reduction operation - An accumulator is an instance of a
BinaryOperator
function of the typeT
1.2 Stream’s collect() Method
Collectors play an important role in Java 8 streams processing. They ‘collect’ the processed elements of the stream into a final representation. Invoking the collect()
method on a Stream, with a Collector instance passed as a parameter ends that Stream’s processing and returns back the final result. Stream.collect()
method is thus a terminal operation. In other words, Stream.collect()
method is used to receive the elements from a stream and store them in a collection.
The collect()
operation accumulates the elements in a stream into a container such as a collection. It performs mutable reduction operation in which the reduced (final) value is a mutable result container such as an ArrayList
. This method takes a Collector
implementation that provides useful reduction operations. The Collectors
class is a common implementation in the ‘JDK 1.8’. The following example accumulates emails of the persons into a list collection.
List<String> listEmails = listPersons.stream().map(p -> p.getEmail()).collect(Collectors.toList()); System.out.println("List of Emails: " + listEmails);
Now, open up the Eclipse Ide and let’s see how to work with Java8 Collectors and Streams API.
2. Java8 Collect vs. Reduce Example
2.1 Tools Used
We are using Eclipse Oxygen, JDK 8 and Maven.
2.2 Project Structure
Firstly, let’s review the final project structure, in case you are confused about where you should create the corresponding files or folder later!
2.3 Project Creation
This section will demonstrate on how to create a Java-based Maven project with Eclipse. In Eclipse IDE, go to File -> New -> Maven Project
.
In the New Maven Project window, it will ask you to select project location. By default, ‘Use default workspace location’ will be selected. Select the ‘Create a simple project (skip archetype selection)’ checkbox and just click on next button to proceed.
It will ask you to ‘Enter the group and the artifact id for the project’. We will input the details as shown in the below image. The version number will be by default: 0.0.1-SNAPSHOT
.
Click on Finish and the creation of a maven project is completed. If you observe, it has downloaded the maven dependencies and a pom.xml
file will be created. It will have the following code:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Java8CollectReduce</groupId> <artifactId>Java8CollectReduce</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> </project>
Developers can start adding the dependencies that they want. Let’s start building the application!
3. Application Building
Below are the steps involved in developing this application.
3.1 Java Class Creation
Let’s create the required Java files. Right-click on the src/main/java
folder, New -> Package
.
A new pop window will open where we will enter the package name as: com.jcg.java
.
Once the package is created in the application, we will need to create the ‘Collect’ and ‘Reduce’ implementation classes to illustrate the implementation of Collectors and Streams API in Java8. Right-click on the newly created package: New -> Class
.
A new pop window will open and enter the file name as: ReduceTest
. The implementation class will be created inside the package: com.jcg.java
.
Repeat the step (i.e. Fig. 7) and enter the filename as: CollectTest
. The implementation class will be created inside the package: com.jcg.java
.
3.1.1 Implementation of Reduce Class
Let’s move to the 1st example where the reduction operation sums up all elements of the stream and the 2nd example where reduction operation finds the employee with the maximum salary. Let’s see the simple code snippet that follows this implementation.
ReduceTest.java
package com.jcg.java; import java.util.Arrays; import java.util.List; import java.util.Optional; public class ReduceTest { static List<Employee> employeeList = Arrays.asList( new Employee("Tom", 45, 7000.00), new Employee("Harry", 25, 10000.00), new Employee("Ethan", 65, 8000.00), new Employee("Nancy", 22, 12000.00), new Employee("Deborah", 29, 9000.00)); public static void main(String[] args) { /***** E.g. #1 - Total Salary Expenses *****/ Double totalSalaryExpense = (Double) employeeList.stream().map(emp -> emp.getSalary()).reduce(0.00,(a,b) -> a+b); System.out.println("Total Salary Expense?= " + totalSalaryExpense + "\n"); /***** E.g. #2 - Employee Details Having Maximum Salary *****/ Optional<Employee> maxSalaryEmp = employeeList.stream().reduce((Employee a, Employee b) -> a.getSalary() < b.getSalary() ? b:a); if(maxSalaryEmp.isPresent()) { System.out.println("Employee with Max. Salary?= "+ maxSalaryEmp.get()); } } }
3.1.2 Implementation of Collector Class
Let’s move to the example where the Stream.collect()
method is used to receive elements from a stream and store them in a collection. Let’s see the simple code snippet that follows this implementation.
CollectTest.java
package com.jcg.java; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class CollectTest { public static void main(String[] args) { List<Employee> empList = new ArrayList<Employee>(); empList.add(new Employee("Tom", 45, 7000.00)); empList.add(new Employee("Harry", 25, 10500.00)); empList.add(new Employee("Ethan", 65, 8000.00)); empList.add(new Employee("Nancy", 22, 12000.00)); empList.add(new Employee("Deborah", 29, 9000.00)); /***** Find Employees Whose Salaries Are Above 10000 *****/ List<Employee> filteredList = empList.stream().filter(emp->emp.getSalary() > 10000).collect(Collectors.toList()); filteredList.forEach(System.out::println); } }
Do remember, developers will have to use the ‘JDK 1.8‘ dependency for implementing this example.
4. Run the Application
To run the application, right-click on the ReduceTest
or the CollectTest
class, Run As -> Java Application
. Developers can debug the example and see what happens after every step!
5. Project Demo
The application shows the following logs as output.
ConsumerTest.java
# Logs for 'ReduceTest' # ========================= Total Salary Expense?= 46000.0 Employee with Max. Salary?= Employee Name: Nancy| Age: 22| Salary: 12000.0 # Logs for 'CollectTest' # ========================== Employee Name: Harry| Age: 25| Salary: 10500.0 Employee Name: Nancy| Age: 22| Salary: 12000.0
That’s all for this post. Happy Learning!
6. Conclusion
In this tutorial, we looked at what are the collect()
and reduce()
methods defined in Java8. I hope this article served developers whatever they were looking for.
7. Download the Eclipse Project
This was an example of collect()
and reduce()
methods in Java8.
You can download the full source code of this example here: Java8CollectReduce