首页 > 解决方案 > 使用 java 8 流对来自不同类的对象进行分组

问题描述

我有以下课程

class Pojo1 {
    pojo2 item;
}

class pojo2 {
    pojo3 item;
}

class pojo3 {
   pojo4 item;
}

我想从 pojo1 流中将它们累积如下。(流多个)

Map<pojo4,Map<pojo3,List<pojo2>>>  k=new HashMap()<>;

谁能帮我在流中做到这一点?我还想根据以下属性对地图进行排序:

   (pojo4 - some property)
   (pojo3 - some property)
   (pojo2- some property)

我想同时使用 java 8 流和并行流来做到这一点。

标签: javajava-stream

解决方案


首先,提到的 POJO 类需要实现Pojo4和才能用作映射键以及属性的相关 getter 。Pojo3hashCodeequals

转换应该使用 common Collectors.groupingBy/Collectors.mapping收集器,并且初始重新映射到需要的两个对象的普通容器Pair

下面的示例使用 Java 11Map.entry作为中间容器。

static Map<Pojo4, <Map<Pojo3, List<Pojo2>>>> convert(Stream<Pojo1> ones) {
    return ones              // Stream<Pojo1>
        .map(Pojo1::getItem) // Stream<Pojo2>
        .map(p2 -> Map.entry(p2, p2.getItem())) // Stream<Map.Entry<Pojo2, Pojo3>>
        .collect(Collectors.groupingBy(
            me -> me.getValue().getItem(), // key: Pojo4
            Collectors.groupingBy(
                me -> me.getValue(), // key: Pojo3
                Collectors.mapping(
                    Map.Entry::getKey, Collectors.toList()
                )
            )
        ));
}

类似地,排序版本可以使用Collectors.groupingBy地图供应商来实现;另外List<Pojo2>应该使用collectingAndThen.

假设Pojo2, Pojo3,具有用于排序的属性的Pojo4getter ,则提供以下更新:getField

static Map<Pojo4, <Map<Pojo3, List<Pojo2>>>> convert(Stream<Pojo1> ones) {
    return ones
        .map(Pojo1::getItem) // Stream<Pojo2>
        .map(p2 -> Map.entry(p2, p2.getItem())) // Stream<Map.Entry<Pojo2, Pojo3>>
        .collect(Collectors.groupingBy(
            me -> me.getValue().getItem(), // key: Pojo4
            () -> new TreeMap(Comparator.comparing(Pojo4::getField)),
            Collectors.groupingBy(
                me -> me.getValue(), // key: Pojo3
                () -> new TreeMap(Comparator.comparing(Pojo3::getField)),
                Collectors.mapping(
                    Map.Entry::getKey, Collectors.collectingAndThen(
                        Collectors.toList(), // List<Pojo2>
                        list -> {
                            list.sort(Comparator.comparing(Pojo2::getField)); 
                            return list;
                        }
                    )
                )
            )
        ));
}

免责声明:上面的代码示例尚未经过测试,因此可能需要进行额外的调整。


推荐阅读