How to use Aggregate functions in Java Streams

Since the introduction of lambda expressions in Java 8, life has become easier for java developers as streams has done away with plenty of boilerplate code. Most of the operations can now be done on the java side for which we had to write complex queries, thanks to the Aggregate functions or Stream Operations.

These aggregate functions process stream data and simplify the day-to-day tasks of programmers such as grouping data by a specific property, finding minimum or maximum from a collection or simply counting the records etc. We will look at some of these operations in action below. First setup a basic java project containing Main.java class, then create a simple class named Employee.java containing the implementation like this:

public class Employee {
private int id;
private String name;
private Integer age;
private LocalDateTime lastUpdated;

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 Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public LocalDateTime getLastUpdated() {
return lastUpdated;
}

public void setLastUpdated(LocalDateTime lastUpdated) {
this.lastUpdated = lastUpdated;
}

@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", lastUpdated=" + lastUpdated.format(DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss")) +
'}';
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return Objects.equals(getName(), employee.getName());
}

@Override
public int hashCode() {
return Objects.hashCode(getName());
}
}

Let’s play with a few of these functions in the Main.java class as shown below.

1. Count the number of employees

long employeeCount = employees.stream().count();
System.out.println("Employee count: " + employeeCount);

2. Find the youngest employee

Employee youngestEmployee = employees.stream().min(Comparator.comparing(Employee::getAge)).orElse(null);
System.out.println("Youngest employee: " + youngestEmployee);

3. Find the oldest employee

Employee oldestEmployee = employees.stream().max(Comparator.comparing(Employee::getAge)).orElse(null);
System.out.println("Oldest employee: " + oldestEmployee);

4. Sum of IDs

int employeeIdSum = employees.stream().mapToInt(Employee::getId).sum();
System.out.println("Sum of employee Ids: " + employeeIdSum);

5. Number of employees with Distinct name

List<Employee> distinctEmployees = employees.stream().distinct().toList();
System.out.println("Distinct employees: ");
printEmployees(distinctEmployees);

6. Group employees by name – Real world use-case could be all employees of a department

Map<String, List<Employee>> groupedEmployees = employees.stream().collect(Collectors.groupingBy(Employee::getName));System.out.println("Grouped employees: " + groupedEmployees);

As we saw in this post, aggregate/stream operations are quite handy and leverage the capabilities of lambda expressions. There are many other operations like average, minBy, maxBy, joining etc. which we have not covered.  Please follow the GitHub repository project setup covering the above mentioned points. Find out more on sorting using streams Here. Thanks and happy coding!!

Leave a comment