Core Java

Grouping, transforming and reduction with Java 8

1. Introduction

In this previous post, I wrote about how we can group collections of objects with streams and grouping. This is useful but does not cover specific use cases. For example, sometimes we do not only need to group things but also transform the result into a more appropriate object.

In this post, we will learn how to apply transformations and reduction to the groupingBy result.

  • Here you can view the source code of the following examples.

2. Grouping by and transform

Let’s take the model I used in the previous post where we had a collection of persons who owned a pet.

Now we want to know which pets belong to persons living in New York. We are asking for pets, so we can’t just make a grouping since we would be returning a collection of persons. What we need to do is group persons by city and then transform the stream to a collection of pets.

For this purpose, we use mapping on the result of the group by:

public void groupAndTransform(List<Person> persons) {
    final Map<String, List<Pet>> petsGroupedByCity = persons.stream().collect(
        groupingBy(
            Person::getCity,
            mapping(Person::getPet, toList())
        )
    );
    
    System.out.println("Pets living in New York: " + petsGroupedByCity.get("NYC"));
}

In the grouping phase, we group persons by city and then perform a mapping to get each person’s pet.

3. Grouping, transforming and reducing

The previous example is useful for converting groupings of objects, but maybe we don’t want to obtain the whole list for each group. In this example, we still want to group pets by its owner’s city, but this time we only want to get the oldest pet of each list.

The method collectingAndThen from Collectors allow us to make a final transformation to the result of the grouping:

public void groupTransformAndReduce(List<Person> persons) {
    final Map<String, Pet> olderPetOfEachCity = persons.stream().collect(
        groupingBy(
            Person::getCity,
            collectOlderPet()
        )
    );
    
    System.out.println("The older pet living in New York is: " + olderPetOfEachCity.get("NYC"));
}

private Collector<Person, ?, Pet> collectOlderPet() {
    return collectingAndThen(
        mapping(
            Person::getPet,
            Collectors.maxBy((pet1, pet2) -> Integer.compare(pet1.getAge(), pet2.getAge()))
        ), Optional::get);
    }

After we group persons by city, in collectingAndThen we are transforming each person in each city’s list to its pet, and then applying a reduction to get the pet with the highest age in the list.

4. Conclusion

Collectors API not only allow us to group collections of things but also make transformations and reductions to obtain different objects depending on our needs.

Xavier Padro

Xavier is a software developer working in a consulting firm based in Barcelona. He is specialized in web application development with experience in both frontend and backend. He is interested in everything related to Java and the Spring framework.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Thanh
Thanh
8 years ago

Great!

Back to top button