Skip to content

Mastering Cascading Collectors in Functional Programming

Posted on:September 6, 2023 at 01:13 PM

Welcome back, coding enthusiasts! In this lecture, we’re about to dive into the intriguing world of cascading collectors. We’ll explore how to efficiently cascade collectors in your code to perform complex operations on your data with ease.

Table of contents

Open Table of contents

Sections

Setting the Stage

Before we embark on our journey through cascading collectors, let’s set the scene. We have a class already set up, and we’re reading data from an employee data file. Using an employee spliterator, we generate a stream of employee objects and store them in an employee list.

But now, let’s take things to the next level. We’re already familiar with the groupingBy collector, which groups data based on a specified criterion, returning a map with lists of employees under different designations. But what if we need more than just lists? What if we want to count employees or calculate the total salary distribution for each designation? This is where cascading collectors come into play.

Counting Employees by Designation

Suppose we want to find out how many employees are there in each designation. We can use a cascading collector to first group employees by their designation and then count them.

Stream<Employee> employees = employeeList.stream();

Map<String, Long> countByDesignation = employees
    .collect(Collectors.groupingBy(Employee::getDesignation, Collectors.counting()));

In this example, we start with a stream of employees and apply the groupingBy collector to group them by designation. However, we’ve added a downstream collector (Collectors.counting()) to calculate the count of employees in each group. The result is a map where designations are keys, and the values represent the count of employees in each designation.

Calculating Total Salary Distribution

Now, let’s tackle a more challenging scenario. We want to determine the total salary distribution for each designation. We start by grouping employees by designation, and then we sum up their salaries.

Stream<Employee> employees = employeeList.stream();

Map<String, Double> fundDistribution = employees
    .collect(Collectors.groupingBy(Employee::getDesignation, Collectors.summingDouble(Employee::getSalary)));

Here, we use the groupingBy collector to group employees by their designation. But the magic happens with the downstream collector Collectors.summingDouble(Employee::getSalary). It calculates the sum of salaries for each group. The result is a map where designations are keys, and the values represent the total salary distribution for each designation.

Finding Employees with the Highest Salary

Now, let’s explore a different use case. We want to find the employee with the highest salary in each designation group.

Stream<Employee> employees = employeeList.stream();

Map<String, Optional<Employee>> maxSalaries = employees
    .collect(Collectors.groupingBy(Employee::getDesignation,
        Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary))));

In this scenario, we again use the groupingBy collector to group employees by designation. However, we employ a different downstream collector, Collectors.maxBy, to find the employee with the highest salary within each group. The result is a map where designations are keys, and the values are Optional instances representing the employees with the highest salaries.

Conclusion

In this lesson, we’ve explored the powerful concept of cascading collectors in functional programming. By chaining collectors together, you can perform complex data transformations efficiently and with clarity. You’ve seen how to count employees by designation, calculate total salary distributions, and find employees with the highest salaries, all in a declarative and concise style.

Keep in mind that while cascading collectors can simplify complex operations, it’s essential to maintain code readability. Avoid excessive nesting of collectors, as it can reduce code clarity. Choose the right collectors for your specific requirements to harness the true power of functional programming.

As you continue your journey into functional programming, you’ll discover a plethora of other collectors that can handle various scenarios. Stay curious, keep coding, and embrace the elegance of functional programming in Java. Until next time, happy coding!

You can find the repo for this section of the course Here