How to use Java 8 Stream Collectors.groupingBy() Examples

How to use Java 8 Stream Collectors.groupingBy()

[no_toc]
In the tutorial, Grokonez will show how to use Grouping By APIs of Java Stream Collectors by examples:

  • Explore Stream GroupingBy Signatures
  • Combine groupingBy API with others Reduction Operations

Now let’s do more details!

Related posts:
Java Stream.Collectors APIs Examples
Java 8 Stream Reduce Examples

Stream GroupingBy Signatures

1. groupingBy(classifier)


public static  Collector>> groupingBy(Function classifier)

-> It returns a Collector implementing a group by operation on input elements of type T,
grouping elements according to a classifier function, and returning the results in a Map.

– Type Parameters:
+ T – the type of the input elements
+ K – the type of the keys

– Parameters:
+ classifier: the classifier function mapping input elements to keys

– Returns: a Collector implementing the cascaded group-by operation

Example:


Map> employeePerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment));

2. groupingBy(classifier, downstream)


public static  Collector> 
	groupingBy(Function classifier,
               Collector downstream)

-> Returns a Collector implementing a cascaded “group by” operation on input elements of type T,
grouping elements according to a classification function, and then performing a reduction operation
on the values associated with a given key using the specified downstream Collector.

– Type Parameters:
+ A: the intermediate accumulation type of the downstream collector
+ D: the result type of the downstream reduction

– Parameters:
+ classifier: a classifier function mapping input elements to keys
+ downstream: a Collector implementing the downstream reduction

Example:


Map> employeePerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.toSet()));

3. groupingBy(classifier, mapFactory, downstream)


public static >
	Collector groupingBy(Function classifier,
							  Supplier mapFactory,
							  Collector downstream) 

-> Returns a Collector implementing a cascaded “group by” operation on input elements of type T,
grouping elements according to a classification function, and then performing a reduction operation
on the values associated with a given key using the specified downstream Collector.

– Parameters:
+ mapFactory: a function which, when called, produces a new empty Map of the desired type

– Example:


Map numberEmployeesPerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, TreeMap::new, Collectors.counting()));

4. GroupingBy Concurrent

We have 3 signatures for Java Stream Collectors GroupingBy Concurrent:

groupingByConcurrent(Function classifier)
groupingByConcurrent(Function classifier, Collector downstream)
groupingByConcurrent(Function classifier, Supplier mapFactory, Collector downstream)

We use groupingByConcurrent as the similar to the groupingBy. But groupingByConcurrent can help us to leverages multi-core architectures to improving performance.
It returns a concurrent, unordered Collector implementing the group-by operation.

Note: mapFactory produces a new empty ConcurrentMap of the desired type.

Example:


Map> employeePerDepartment = employees.parallelStream().collect(
		Collectors.groupingByConcurrent(Employee::getDepartment, ConcurrentSkipListMap::new, Collectors.mapping(Employee::getName, Collectors.toSet())));

Java Stream Collectors GroupingBy Examples

Setup Models

– Create Employee.java class:


class Employee{
    private String name;
    private DepartmentType department;
    private City city;
    private int salary;
  
    Employee(String name, DepartmentType department, City city, int salary){
    	this.name = name;
    	this.department  = department;
    	this.city = city;
    	this.salary = salary;
    }
    
    public String getName() {
    	return this.name;
    }
  
    public DepartmentType getDepartment() {
    	return this.department;
    }
    
    public City getCity() {
    	return this.city;
    }
    
    public int getSalary() {
    	return this.salary;
    }
  
    public String toString() {
    	return String.format("{name = %s, department = %s, city =%s, salary = %d}", this.name, this.department, this.city, this.salary);
    }
}

enum DepartmentType {
	SOFTWARE,
	FINANCE,
	HR
}

enum City {
	ALBANY,
	PARMA,
	WILMINGTON,
	HAMMOND
}

– Init Employee List:


List employees = Arrays.asList(new Employee("Jack", DepartmentType.SOFTWARE, City.ALBANY,7400),
        new Employee("Joe", DepartmentType.FINANCE, City.WILMINGTON, 6200),
        new Employee("Jane", DepartmentType.HR, City.PARMA, 7300),
        new Employee("Mary", DepartmentType.FINANCE, City.WILMINGTON, 5700),
        new Employee("Peter", DepartmentType.SOFTWARE, City.ALBANY, 8400),
        new Employee("Davis", DepartmentType.FINANCE, City.WILMINGTON, 6100),
        new Employee("Harry", DepartmentType.FINANCE, City.HAMMOND, 6800)
      );

Nested GroupingBy


Map>> cityDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.groupingBy(Employee::getCity)));

System.out.println(cityDepartment);

-> Output:


/*
 * {	
 * 		FINANCE={
 * 					HAMMOND=[
 * 									{name = Harry, department = FINANCE, city =HAMMOND, salary = 6800}], 
 * 					WILMINGTON=[
 * 									{name = Joe, department = FINANCE, city =WILMINGTON, salary = 6200}, 
 * 									{name = Mary, department = FINANCE, city =WILMINGTON, salary = 5700}, 
 * 									{name = Davis, department = FINANCE, city =WILMINGTON, salary = 6100}]}, 
 * 		SOFTWARE={	
 * 					ALBANY=[
 * 								{name = Jack, department = SOFTWARE, city =ALBANY, salary = 7400}, 
 * 								{name = Peter, department = SOFTWARE, city =ALBANY, salary = 8400}]}, 
 * 		HR={
 * 					PARMA=[
 * 								{name = Jane, department = HR, city =PARMA, salary = 7300}]}}
 */

Summing Results after GroupingBy


Map sumSalariesByDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.summingInt(Employee::getSalary)));

System.out.println(sumSalariesByDepartment);

-> Output:


/*
 * {HR=7300, SOFTWARE=15800, FINANCE=24800}
 */

Getting Max/Min Values after GroupingBy

– Getting Max salaries per each department:


Map> maxSalaryPerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.maxBy(Comparator.comparingInt(Employee::getSalary))));

System.out.println(maxSalaryPerDepartment);

-> Output:


/*
 * {	
 * 		SOFTWARE= Optional[{name = Peter, department = SOFTWARE, city =ALBANY, salary = 8400}], 
 * 		HR=Optional[{name = Jane, department = HR, city =PARMA, salary = 7300}], 
 * 		FINANCE=Optional[{name = Harry, department = FINANCE, city =HAMMOND, salary = 6800}]
 * }
 */	

– Getting Min salaries per each department:


Map> minSalaryPerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.minBy(Comparator.comparingInt(Employee::getSalary))));

System.out.println(minSalaryPerDepartment);

-> Output:


/*
 * {
 * 		FINANCE=Optional[{name = Mary, department = FINANCE, city =WILMINGTON, salary = 5700}], 
 * 		SOFTWARE=Optional[{name = Jack, department = SOFTWARE, city =ALBANY, salary = 7400}], 
 * 		HR=Optional[{name = Jane, department = HR, city =PARMA, salary = 7300}]}
 */

Summarizing Result after GroupingBy Example


Map summarizingSalaryPerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.summarizingDouble(Employee::getSalary)));

System.out.println(summarizingSalaryPerDepartment);

-> Output:


/*
 * {
 * 		HR=DoubleSummaryStatistics{count=1, sum=7300,000000, min=7300,000000, average=7300,000000, max=7300,000000}, 
 * 		SOFTWARE=DoubleSummaryStatistics{count=2, sum=15800,000000, min=7400,000000, average=7900,000000, max=8400,000000}, 
 * 		FINANCE=DoubleSummaryStatistics{count=4, sum=24800,000000, min=5700,000000, average=6200,000000, max=6800,000000}
 * }	
 */

Mapping Results after GroupingBy


Map> employeePerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.mapping(Employee::getName, Collectors.toList())));

System.out.println(employeePerDepartment);

-> Output:


/*
 * {
 * 		SOFTWARE=[Jack, Peter], 
 * 		HR=[Jane], 
 * 		FINANCE=[Joe, Mary, Davis, Harry]
 * }
 */

Partitioning Results after GroupingBy


Map>> partitioningSalaryPerDepartment = employees.stream().collect(
		Collectors.groupingBy(Employee::getDepartment, Collectors.partitioningBy(e -> e.getSalary() > 7500)));

System.out.println(partitioningSalaryPerDepartment);

-> Output:


/*
 * {
 * 		HR={
 * 				false=[
 * 						{name = Jane, department = HR, city =PARMA, salary = 7300}
 * 				], 
 * 				true=[]
 * 		}, 
 * 		SOFTWARE={
 * 				false=[
 * 						{name = Jack, department = SOFTWARE, city =ALBANY, salary = 7400}
 * 				], 
 * 				true=[
 * 						{name = Peter, department = SOFTWARE, city =ALBANY, salary = 8400}
 * 				]
 * 		}, 
 * 		FINANCE={
 * 				false=[
 * 						{name = Joe, department = FINANCE, city =WILMINGTON, salary = 6200}, 
 * 						{name = Mary, department = FINANCE, city =WILMINGTON, salary = 5700}, 
 * 						{name = Davis, department = FINANCE, city =WILMINGTON, salary = 6100}, 
 * 						{name = Harry, department = FINANCE, city =HAMMOND, salary = 6800}
 * 				], 
 * 				true=[]
 * 		}
 * }
 */

Conclusion

We had learned how to use Java Stream Collectors GroupingBy APIs by examples:

  • Explain how to use GroupingBy APIs with many variant signatures
  • Apply GroupingBy APIs with other Stream Reduction Operations: Min/Max, Summarizing, Mapping, Partitioning

Thanks so much! Happy Learning!

4 thoughts on “How to use Java 8 Stream Collectors.groupingBy() Examples”

  1. I just could not leave your website before suggesting that I actually enjoyed the standard info a person provide on your visitors? Is going to be again incessantly in order to check up on new posts.

Leave a Reply

Your email address will not be published. Required fields are marked *