Introduction
In this guide we will learn how to use Collectors
Utility in Java.
It provides implementations of Collector that implement various useful reduce operations such as accumulating
elements into collections, summarizing elements according to various criteria.
Let us check how to use Collectors utility with examples.
Consider a employee class as shown below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class Employee {
private String empId ;
private String empName ;
private int salary ;
private String deptName ;
private int age ;
public Employee ( String empId , String empName
, int salary , String deptName , int age ) {
this . empId = empId ;
this . empName = empName ;
this . salary = salary ;
this . deptName = deptName ;
this . age = age ;
}
@Override
public String toString () {
return "Employee{" +
"empId='" + empId + '\'' +
", empName='" + empName + '\'' +
", salary=" + salary +
", deptName='" + deptName + '\'' +
", age=" + age +
'}' ;
}
public String getEmpId () {
return empId ;
}
public void setEmpId ( String empId ) {
this . empId = empId ;
}
public String getEmpName () {
return empName ;
}
public void setEmpName ( String empName ) {
this . empName = empName ;
}
public int getSalary () {
return salary ;
}
public void setSalary ( int salary ) {
this . salary = salary ;
}
public String getDeptName () {
return deptName ;
}
public void setDeptName ( String deptName ) {
this . deptName = deptName ;
}
public int getAge () {
return age ;
}
public void setAge ( int age ) {
this . age = age ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
List < Employee > employees = new ArrayList <>();
Employee emp1 = new Employee ( "1" , "Tim" , 10000 , "Sales" , 30 );
Employee emp2 = new Employee ( "2" , "Jim" , 5000 , "Developer" , 25 );
Employee emp3 = new Employee ( "3" , "Zara" , 8000 , "Developer" , 33 );
Employee emp4 = new Employee ( "4" , "Mary" , 11000 , "Marketing" , 40 );
Employee emp5 = new Employee ( "5" , "Rocky" , 12000 , "Developer" , 39 );
employees . add ( emp1 );
employees . add ( emp2 );
employees . add ( emp3 );
employees . add ( emp4 );
employees . add ( emp5 );
Collectors.toList: Collecting processed elements into different collection
Using Collectors.toList()
we can collect processed elements into different collection i.e List
1
2
3
4
5
6
7
List < Employee > filteredEmployee =
employees . stream ()
. filter ( e -> e . getSalary () > 10000 )
. collect ( Collectors . toList ());
System . out . println ( filteredEmployee );
//[Employee{empId='4', empName='Mary', salary=11000, deptName='Marketing', age=40}, Employee{empId='5', empName='Rocky', salary=12000, deptName='Developer', age=39}]
If we want to collect to read only collection which cannot be modified we can use Collectors.toUnmodifiableList()
.
1
2
3
4
5
6
7
List < Employee > filteredEmployee =
employees . stream ()
. filter ( e -> e . getSalary () > 10000 )
. collect ( Collectors . toUnmodifiableList ());
System . out . println ( filteredEmployee );
//[Employee{empId='4', empName='Mary', salary=11000, deptName='Marketing', age=40}, Employee{empId='5', empName='Rocky', salary=12000, deptName='Developer', age=39}]
Collectors.groupingBy: Grouping collection by department
We can group elements in the collection by using department name by using Collectors.groupingBy()
.
It returns a Map<String, List> where key represents groupid(department name) and list contains employees
belonging to that group.
1
2
3
4
5
6
7
8
Map < String , List < Employee >> group =
employees . stream ()
. collect ( Collectors . groupingBy ( e -> e . getDeptName ()));
System . out . println ( group . keySet ());
System . out . println ( group );
//[Sales, Developer, Marketing]
// {Sales=[Employee{empId='1', empName='Tim', salary=10000, deptName='Sales', age=30}], Developer=[Employee{empId='2', empName='Jim', salary=5000, deptName='Developer', age=25}, Employee{empId='3', empName='Zara', salary=8000, deptName='Developer', age=33}, Employee{empId='5', empName='Rocky', salary=12000, deptName='Developer', age=39}], Marketing=[Employee{empId='4', empName='Mary', salary=11000, deptName='Marketing', age=40}]}
Using Collectors.summarizingInt()
we can get useful statistics for the input values processed by the stream.
In the below example we would gather statistics for the salary of the employee.
1
2
3
4
5
6
7
8
9
IntSummaryStatistics statistics =
employees
. stream ()
. collect ( Collectors . summarizingInt ( s -> s . getSalary ()));
System . out . println ( "Count: " + statistics . getCount ()+ " Average: " + statistics . getAverage ()
+ " Max: " + statistics . getMax () + " Min: " + statistics . getMin ()+ " Sum: " + statistics . getSum ());
// Count: 5 Average: 9200.0 Max: 12000 Min: 5000 Sum: 46000
To partition input elements into 2 groups based on a predicate we can use Collectors.partitioningBy
.
One group contains values which have met predicate condition and other which has not.
In the below example employees are partitioned into 2 groups based on salary > 10000
1
2
3
4
5
6
7
8
Map < Boolean , List < Employee >> partitionBySalary =
employees . stream ()
. collect ( Collectors . partitioningBy ( e -> e . getSalary () > 10000 ));
System . out . println ( "True: " + partitionBySalary . get ( true ));
System . out . println ( "False: " + partitionBySalary . get ( false ));
//True: [Employee{empId='4', empName='Mary', salary=11000, deptName='Marketing', age=40}, Employee{empId='5', empName='Rocky', salary=12000, deptName='Developer', age=39}]
//False: [Employee{empId='1', empName='Tim', salary=10000, deptName='Sales', age=30}, Employee{empId='2', empName='Jim', salary=5000, deptName='Developer', age=25}, Employee{empId='3', empName='Zara', salary=8000, deptName='Developer', age=33}]
We can concatenate the input elements processed by a given delimiter using Collectors.joining()
method.
In the below example we take employee name from the employee object and concatenated them using delimiter ‘,’.
1
2
3
4
5
6
7
8
String joinedEmployeeNames =
employees
. stream ()
. map ( Employee :: getEmpName )
. collect ( Collectors . joining ( "," ));
System . out . println ( joinedEmployeeNames );
// Tim,Jim,Zara,Mary,Rocky
We can sort the input elements processed by Stream by storing them into TreeSet.
To sort elements we need to specify Comparator
as an argument to the TreeSet.
In the below example we are sorting by employee id.
1
2
3
4
5
6
7
8
TreeSet < Employee > sortedEmployee =
employees . stream ()
. collect ( Collectors . toCollection (() ->
new TreeSet <>( Comparator . comparing ( e -> e . getEmpId ()))));
System . out . println ( sortedEmployee );
//[Employee{empId='1', empName='Tim', salary=10000, deptName='Sales', age=30}, Employee{empId='2', empName='Jim', salary=5000, deptName='Developer', age=25}, Employee{empId='3', empName='Zara', salary=8000, deptName='Developer', age=33}, Employee{empId='4', empName='Mary', salary=11000, deptName='Marketing', age=40}, Employee{empId='5', empName='Rocky', salary=12000, deptName='Developer', age=39}]