$show=/label

Java 8 Streams - Group By Multiple Fields with Collectors.groupingBy()

SHARE:

A guide to group by two or more fields in java 8 streams api. Examples to grouping List by two fields.

1. Overview

In this tutorial, We will learn how to group by multiple fields in java 8 using Streams Collectors.groupingBy() method and example programs with custom objects.

In the previous article, We have shown how to perform Group By in java 8 with Collectors API?

Java 8 Streams - Group By Multiple Fields



2. Group By Multiple Fields Example in Java 8


First, Create a class Employee with the below properties.

int id
String name
String designation
String gender
long salary

Create argument constructor and setter, getters methods for all properties. And also add toString() method to see the Employee object in a readable format.

Next, We will try to implement the group by on two fields such as designation and gender. On these two fields get the group by count.

Look at the below examples, you will see the code with the groupingBy() is used twice. This is called as Collectors chaining and observing the output.

package com.javaprogramto.java8.collectors.groupby;

public class Employee {

	private int id;
	private String name;
	private String designation;
	private String gender;
	private long salary;

	public Employee(int id, String name, String designation, String gender, long salary) {
		super();
		this.id = id;
		this.name = name;
		this.designation = designation;
		this.gender = gender;
		this.salary = salary;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDesignation() {
		return designation;
	}

	public void setDesignation(String designation) {
		this.designation = designation;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public long getSalary() {
		return salary;
	}

	public void setSalary(long salary) {
		this.salary = salary;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", designation=" + designation + ", gender=" + gender
				+ ", salary=" + salary + "]";
	}
}
 
Example - Group By Two Properties:

package com.javaprogramto.java8.collectors.groupby;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GroupingByMultipleFieldsExample {

	public static void main(String[] args) {

		// Creating List and adding Employees values.
		List<Employee> employeesList = new ArrayList<>();

		employeesList.add(new Employee(101, "Glady", "Manager", "Male", 25_00_000));
		employeesList.add(new Employee(102, "Vlad", "Software Engineer", "Female", 15_00_000));
		employeesList.add(new Employee(103, "Shine", "Lead Engineer", "Female", 20_00_000));
		employeesList.add(new Employee(104, "Nike", "Manager", "Female", 25_00_000));
		employeesList.add(new Employee(105, "Slagan", "Software Engineer", "Male", 15_00_000));
		employeesList.add(new Employee(106, "Murekan", "Software Engineer", "Male", 15_00_000));
		employeesList.add(new Employee(107, "Gagy", "Software Engineer", "Male", 15_00_000));

		// group by - multiple fields
		// Grouping by designation and Gender two properties and need to get the count.

		Map<String, Map<String, Long>> multipleFieldsMap = employeesList.stream()
				.collect(
						Collectors.groupingBy(Employee::getDesignation, 
								Collectors.groupingBy(Employee::getGender, 
										Collectors.counting())));

		// printing the count based on the designation and gender.
		System.out.println("Group by on multiple properties" + multipleFieldsMap);
	}
}
 
Output:
Group by on multiple properties
{Software Engineer={Male=3, Female=1}, Manager={Female=1, Male=1}, Lead Engineer={Female=1}}
 
From the output, you can clearly observe that we can see the count by designation and gender type.

In this program, we have gathered the count of employees but rather than this, we can get the list of Employees.


3. Java 8 - Group By Multiple Fields and Collect Aggregated Result into List


First, Collect the list of employees as List<Employee> instead of getting the count. That means the inner aggregated Map value type should be List.

To get the list, we should not pass the second argument for the second groupingBy() method.

// Example 2
// group by - multiple fields
// Grouping by designation and Gender two properties and need to get the count.

Map<String, Map<String, List<Employee>>> multipleFieldsMapList = employeesList.stream()
		.collect(
				Collectors.groupingBy(Employee::getDesignation, 
						Collectors.groupingBy(Employee::getGender)));

// printing the count based on the designation and gender.
System.out.println("Group by on multiple properties and Map key as List" + multipleFieldsMapList);
 

Output:

Group by on multiple properties and Map key as List 
{
Software Engineer={Male=[
						Employee [id=105, name=Slagan, designation=Software Engineer, gender=Male, salary=1500000], Employee [id=106, name=Murekan, designation=Software Engineer, gender=Male, salary=1500000], Employee [id=107, name=Gagy, designation=Software Engineer, gender=Male, salary=1500000]], 
					Female=[Employee [id=102, name=Vlad, designation=Software Engineer, gender=Female, salary=1500000]]}, 
Manager={
		Female=[Employee [id=104, name=Nike, designation=Manager, gender=Female, salary=2500000]], 
		Male=[Employee [id=101, name=Glady, designation=Manager, gender=Male, salary=2500000]]}, 
Lead Engineer={Female=[Employee [id=103, name=Shine, designation=Lead Engineer, gender=Female, salary=2000000]]}}

 

4. Java 8 - Group By Multiple Fields - Avoid Collectors Chaining


We can avoid the Collectors chaining such as calling groupingby() function several times. If we want to group by 4 fields then need to call Collectors.groupingBy() also 4 times which makes code ugly and not readable.

Let us create the separate class with the group by properties and write implementation for equals(), hashcode() methods for object comparisons.

Creating a new class for GroupBy fields makes us to call only once the groupingBy() method.

The below examples are implemented as described and suggested way.

GroupBy Class:

class GroupBy {

	private String designation;
	private String gender;

	public GroupBy(String designation, String gender) {
		super();
		this.designation = designation;
		this.gender = gender;
	}

	@Override
	public int hashCode() {

		return this.designation.length() + this.gender.length();
	}

	@Override
	public boolean equals(Object obj) {

		GroupBy other = (GroupBy) obj;

		if (other.getDesignation().equals(this.designation) && other.getGender().equals(this.gender))
			return true;
		return false;
	}

	public String getDesignation() {
		return designation;
	}

	public void setDesignation(String designation) {
		this.designation = designation;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	@Override
	public String toString() {
		return "GroupBy [designation=" + designation + ", gender=" + gender + "]";
	}
}
 
Employee Class:

package com.javaprogramto.java8.collectors.groupby.multiple;

public class Employee {

	private int id;
	private String name;
	private long salary;
	private GroupBy groupBy;

	public Employee(int id, String name, long salary, GroupBy groupBy) {
		super();
		this.id = id;
		this.name = name;
		this.salary = salary;
		this.groupBy = groupBy;
	}

	// setters and getters

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", groupBy=" + groupBy + "]";
	}
}

 
Optimized Group By Multiple Fields Example  

package com.javaprogramto.java8.collectors.groupby.multiple;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GroupingByMultipleFieldsExample {

	public static void main(String[] args) {

		// Creating List and adding Employees values.
		List<Employee> employeesList = new ArrayList<>();

		employeesList.add(new Employee(101, "Glady", 25_00_000, new GroupBy("Manager", "Male")));
		
		employeesList.add(new Employee(102, "Vlad", 15_00_000, new GroupBy("Software Engineer", "Female")));
		employeesList.add(new Employee(103, "Shine", 20_00_000, new GroupBy("Lead Engineer", "Female")));
		employeesList.add(new Employee(104, "Nike", 25_00_000, new GroupBy("Manager", "Female")));
		employeesList.add(new Employee(105, "Slagan", 15_00_000, new GroupBy("Software Engineer", "Male")));
		employeesList.add(new Employee(106, "Murekan", 15_00_000, new GroupBy("Software Engineer", "Male")));
		employeesList.add(new Employee(107, "Gagy", 15_00_000, new GroupBy("Software Engineer", "Male")));

		// Example 1
		// group by - multiple fields
		// Grouping by designation and Gender two properties and need to get the count.

		Map<GroupBy, Long> multipleFieldsMap = employeesList.stream()
				.collect(Collectors.groupingBy(Employee::getGroupBy, Collectors.counting()));

		// printing the count based on the designation and gender.
		System.out.println("Group by on multiple properties" + multipleFieldsMap);
	}
}
 
Output:
Group by on multiple properties
	{ GroupBy [designation=Lead Engineer, gender=Female]=1, 
	  GroupBy [designation=Software Engineer, gender=Male]=3, 
	  GroupBy [designation=Software Engineer, gender=Female]=1, 
	  GroupBy [designation=Manager, gender=Male]=1, 
	  GroupBy [designation=Manager, gender=Female]=1
	}
 

We can record feature from Java 14 alternative to the separate class for group by properties.

5. Grouping By Using Apache Commons Pair.of()

If you have only two fields and do not wish to use the Record or Another class with the Group by properties then we can use the Pair.of() from apache commons library.

// Example 3
// group by - multiple fields
// Grouping by designation and Gender two properties with Pair.of()

Map<Pair<String, String>, Long> multipleFieldsMapPair = employeesList.stream()
		.collect(Collectors.groupingBy(e -> Pair.of(e.getDesignation(), e.getGender()), Collectors.counting()));

// printing the count based on the designation and gender.
System.out.println("Group by on multiple fields with Pair - " + multipleFieldsMapPair);
 

Output:
Group by on multiple fields with Pair - 
{
	(Software Engineer,Male)=3, 
	(Software Engineer,Female)=1, 
	(Lead Engineer,Female)=1, 
	(Manager,Female)=1, 
	(Manager,Male)=1
}
 

6. Conclusion

In this article, We have seen how to work with the multiple fields in group by using Collectors.groupingBy() method.

Example program to show the best and maintainable code if we have more than 3 fields in the group by combination then we have to go with the custom group by class.

Use the apache Pair class if you have only two group-by properties.


COMMENTS

BLOGGER: 2
  1. How to do it if I have a class with public final fields and no getters?

    ReplyDelete
    Replies
    1. Hi Stach,

      When you say final, are these static fields? If it static, then you no need to use the group by. Because all the object you add to the collection will be the same type of static field.

      Static complete guide here
      https://www.javaprogramto.com/2013/08/static-in-java.html


      If it is only a final, it is not advisable to set the values using object.finalField. Please add setters and getters.

      Delete
Please do not add any spam links in the comments section.

About Us

Author: Venkatesh - I love to learn and share the technical stuff.
Name

accumulo,1,ActiveMQ,2,Adsense,1,API,37,ArrayList,18,Arrays,24,Bean Creation,3,Bean Scopes,1,BiConsumer,1,Blogger Tips,1,Books,1,C Programming,1,Collection,8,Collections,37,Collector,1,Command Line,1,Comparator,1,Compile Errors,1,Configurations,7,Constants,1,Control Statements,8,Conversions,6,Core Java,149,Corona India,1,Create,2,CSS,1,Date,3,Date Time API,38,Dictionary,1,Difference,2,Download,1,Eclipse,3,Efficiently,1,Error,1,Errors,1,Exceptions,8,Fast,1,Files,17,Float,1,Font,1,Form,1,Freshers,1,Function,3,Functional Interface,2,Garbage Collector,1,Generics,4,Git,9,Grant,1,Grep,1,HashMap,2,HomeBrew,2,HTML,2,HttpClient,2,Immutable,1,Installation,1,Interview Questions,6,Iterate,2,Jackson API,3,Java,32,Java 10,1,Java 11,6,Java 12,5,Java 13,2,Java 14,2,Java 8,128,Java 8 Difference,2,Java 8 Stream Conversions,4,java 8 Stream Examples,12,Java 9,1,Java Conversions,14,Java Design Patterns,1,Java Files,1,Java Program,3,Java Programs,114,Java Spark,1,java.lang,4,java.util. function,1,JavaScript,1,jQuery,1,Kotlin,11,Kotlin Conversions,6,Kotlin Programs,10,Lambda,2,lang,29,Leap Year,1,live updates,1,LocalDate,1,Logging,1,Mac OS,3,Math,1,Matrix,6,Maven,1,Method References,1,Mockito,1,MongoDB,3,New Features,1,Operations,1,Optional,6,Oracle,5,Oracle 18C,1,Partition,1,Patterns,1,Programs,1,Property,1,Python,2,Quarkus,1,Read,1,Real Time,1,Recursion,2,Remove,2,Rest API,1,Schedules,1,Serialization,1,Servlet,2,Sort,1,Sorting Techniques,8,Spring,2,Spring Boot,23,Spring Email,1,Spring MVC,1,Streams,31,String,61,String Programs,28,String Revese,1,StringBuilder,1,Swing,1,System,1,Tags,1,Threads,11,Tomcat,1,Tomcat 8,1,Troubleshoot,26,Unix,3,Updates,3,util,5,While Loop,1,
ltr
item
JavaProgramTo.com: Java 8 Streams - Group By Multiple Fields with Collectors.groupingBy()
Java 8 Streams - Group By Multiple Fields with Collectors.groupingBy()
A guide to group by two or more fields in java 8 streams api. Examples to grouping List by two fields.
https://blogger.googleusercontent.com/img/a/AVvXsEiZNn4FSahd3Vaw-KdqdJw23xF-_JuzXDO3I_OW2f9DixhPEkJDyDLdUIjf4TWKSQdpu3yTGmD29X5ybZcMPoiZocxHOdMFLU35m9lENzCxwzNKVcwN8SFu99YxMpEJzcz_zKevjXEeXLQZxN2ZcFuy0rS2m6REyK8--e_FVReB9UT7qH7VhOGy5ltV=w400-h223
https://blogger.googleusercontent.com/img/a/AVvXsEiZNn4FSahd3Vaw-KdqdJw23xF-_JuzXDO3I_OW2f9DixhPEkJDyDLdUIjf4TWKSQdpu3yTGmD29X5ybZcMPoiZocxHOdMFLU35m9lENzCxwzNKVcwN8SFu99YxMpEJzcz_zKevjXEeXLQZxN2ZcFuy0rS2m6REyK8--e_FVReB9UT7qH7VhOGy5ltV=s72-w400-c-h223
JavaProgramTo.com
https://www.javaprogramto.com/2021/02/java-8-streams-group-by-multiple-fields.html
https://www.javaprogramto.com/
https://www.javaprogramto.com/
https://www.javaprogramto.com/2021/02/java-8-streams-group-by-multiple-fields.html
true
3124782013468838591
UTF-8
Loaded All Posts Not found any posts VIEW ALL Readmore Reply Cancel reply Delete By Home PAGES POSTS View All RECOMMENDED FOR YOU LABEL ARCHIVE SEARCH ALL POSTS Not found any post match with your request Back Home Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sun Mon Tue Wed Thu Fri Sat January February March April May June July August September October November December Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec just now 1 minute ago $$1$$ minutes ago 1 hour ago $$1$$ hours ago Yesterday $$1$$ days ago $$1$$ weeks ago more than 5 weeks ago Followers Follow THIS PREMIUM CONTENT IS LOCKED STEP 1: Share to a social network STEP 2: Click the link on your social network Copy All Code Select All Code All codes were copied to your clipboard Can not copy the codes / texts, please press [CTRL]+[C] (or CMD+C with Mac) to copy Table of Content