Skip to content

Harnessing the Power of Collectors in Functional Programming

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

Greetings, fellow learners! Welcome back to our exploration of the captivating world of functional programming. Today, we dive headfirst into the realm of Collectors—a powerful arsenal in the functional programmer’s toolkit. But first, let’s briefly recap what we’ve learned so far.

In our previous session, we introduced Collectors and hinted at their ability to simplify the process of accumulating, summarizing, and aggregating data in streams. We saw that these remarkable tools can transform complex data-handling tasks into elegant one-liners. Now, it’s time to unravel the depths of the Collectors API.

Table of contents

Open Table of contents

Sections

Getting Acquainted with the Collectors API

No more preamble; let’s witness Collectors in action! On your screen is a dataset of employees working for an IT organization. Each line represents an employee’s information, including their ID, name, gender, date of birth, city, designation, joining date, and annual salary. We’ve also prepared a Java bean, Employee.java, to represent this data.

Our journey begins by creating a Stream from this dataset. We employ the Files.lines method to read the lines from the file and convert them into a stream. However, this stream isn’t precisely what we need—it contains lines of text, not the employee objects we desire.

Crafting a Custom Spliterator

To transform this stream of lines into a stream of employee objects, we’ll need a custom spliterator. This is where things get interesting! First, we obtain a stream of words from the lines by splitting each line at commas. This gives us a single, flattened stream of words from all the lines.

Now, we can create our custom spliterator for reading employee objects. We build this spliterator on top of the word spliterator. This custom spliterator will read the words in groups of eight (one for each field of an employee), construct an Employee object, and return it.

To see it in action, we print the employee objects in the stream and ensure that our custom spliterator is working as expected.

Leveraging the Power of Collectors

With our stream of employee objects ready, we’re set to unleash the power of Collectors. We’ll explore two common use cases:

1 - Creating a List of Employee Names Imagine you need a list containing the names of all the employees. It’s a straightforward task:

List<String> employeeNames = employees
    .map(Employee::getName) // Extract employee names
    .collect(Collectors.toList()); // Collect names into a list

We apply the map operation to extract the employee names and then use the collect method with Collectors.toList() to collect them into a list.

2 - Obtaining a Set of Employee Designations

Now, let’s say you want to find out all the unique designations held by employees. It’s equally simple:

Set<String> designations = employees
    .map(Employee::getDesignation) // Extract employee designations
    .collect(Collectors.toSet()); // Collect designations into a set

Again, we employ the map operation to extract the designations and use Collectors.toSet() to collect them into a set. This approach ensures that we have no duplicate entries.

The Gift of Immutability

For added peace of mind, you can create unmodifiable lists and sets using methods like Collections.unmodifiableList and Collections.unmodifiableSet. These provide protection against accidental modifications after creation.

And that, dear learners, is just the tip of the iceberg! Collectors offer a wide array of methods to cater to various collection and aggregation needs. In our next session, we’ll delve deeper into the world of Collectors, uncovering even more useful techniques.

Stay curious, stay focused, and stay tuned as we continue to explore the infinite possibilities of functional programming!

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