"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > How to Implement Multi-Level Grouping with Nested Objects in Java 8?

How to Implement Multi-Level Grouping with Nested Objects in Java 8?

Published on 2024-11-07
Browse:303

How to Implement Multi-Level Grouping with Nested Objects in Java 8?

Multi-Level Grouping in Java 8 Using Nested GroupBy

This article explores how to implement multi-level grouping when dealing with nested classes in Java 8. Specifically, the goal is to group items by a key1 field and then, for each group of items, further group them by a key2 field. Ultimately, the output should be a map with key1 as the outer key and a map of key2 to a list of subitems.

The initial approach attempts to use the Collectors.groupingBy method to achieve this, however, it is not possible to group a single item by multiple keys directly. To overcome this, a flatMap operation is utilized.

One method involves creating a temporary pair using Map.entrySet to hold combinations of items and subitems before collecting. The other approach, available in Java 9, leverages the flatMapping collector, which enables performing the flatMap operation directly in the collector.

Here's the flatMap solution:

Map>> result = pojo.getItems().stream()
    .flatMap(item -> item.getSubItems().stream()
        .map(sub -> new AbstractMap.SimpleImmutableEntry(item.getKey1(), sub)))
    .collect(Collectors.groupingBy(AbstractMap.SimpleImmutableEntry::getKey,
                Collectors.mapping(Map.Entry::getValue,
                    Collectors.groupingBy(SubItem::getKey2))));

An alternative using a custom collector in Java 8:

static  Collector flatMapping(
    Function super T,? extends Stream extends U>> mapper,
    Collector super U,A,R> downstream) {

    BiConsumer acc = downstream.accumulator();
    return Collector.of(downstream.supplier(),
        (a, t) -> { try(Stream extends U> s=mapper.apply(t)) {
            if(s!=null) s.forEachOrdered(u -> acc.accept(a, u));
        }},
        downstream.combiner(), downstream.finisher(),
        downstream.characteristics().toArray(new Collector.Characteristics[0]));
}

This custom collector can be used as follows:

Map>> result = pojo.getItems().stream()
    .collect(Collectors.groupingBy(Item::getKey1,
                Collectors.flatMapping(item -> item.getSubItems().stream(),
                    Collectors.groupingBy(SubItem::getKey2))));
Release Statement This article is reprinted at: 1729730703 If there is any infringement, please contact [email protected] to delete it
Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3