Java 8收集器链接嵌套1到多个关系

时间:2016-10-25 08:36:03

标签: java-8

我正在使用java 8流和收集器来迭代集合。在操作结束时,我必须将流中包含的对象转换为相关的业务对象。并且这些业务对象具有1到多的关系。 以下是清楚的描述所使用的类。

第一个是Helper类,代表我将在我的流上收集的集合。

public class Helper{
    private String a;
    private String additionalA;
    private String additionalB;
    private String additionalC;
    //constructor, setter, getter, equals, hashCode omitted.
} 

Bean A是单一的bean没有关系,只是原语。

public class BeanA{
        private String a;
        private String additionalA;
        //constructor, setter, getter, equals, hashCode omitted.
}

Bean B与Bean A以及其他信息有1对多的关系

public class BeanB{
        private List<BeanA> beanA = new ArrayList<BeanA>();
        private String additonalB;
       //constructor, setter, getter, equals, hashCode omitted.
}

BeanC与BeanB以及其他信息有1对多的关系

public static class BeanC {
        private List<BeanB> beanB = new ArrayList<BeanB>();
        private String additionalC;
        //constructor, setter, getter, equals, hashCode omitted.
}

此外,我还有几种转换方法,例如:

public static BeanA getBeanA(Helper helper) {
    BeanA a = new BeanA();
    a.setA(helper.getA());
    a.setAdditionalA(helper.getAdditionalA());
    return a;
}

public static BeanB getBeanB(Helper helper) {
    BeanB b = new BeanB();
    //maybe wrong to add the data to list (see below)
    b.getBeanA().add(getBeanA(helper));
    b.setAdditonalB(helper.getAdditionalB());
    return b;
}

public static BeanC getBeanC(Helper helper) {
    BeanC c = new BeanC();
    //maybe wrong to add the data to list (see below)
    c.getBeanB().add(getBeanB(helper));
    c.setAdditionalC(helper.getAdditionalC());
    return c;

}

,预期结果是地图

Map<BeanC,Map<BeanB,List<BeanA>>> 

我有 用于产生所需结果的以下块:

Map<BeanC, Map<BeanB, List<BeanA>>> res = helpers.stream()
                .collect(Collectors.groupingBy(
                        Test::getBeanC,
                        Collectors.groupingBy(Test::getBeanB, 
                                Collectors.collectingAndThen(Collectors.toList(), 
                                        list -> list.stream()
                                                    .map(Test::getBeanA)
                                                    .collect(Collectors.toList())))));

问题是BeanC和BeanB上的列表设置不正确。

任何人都知道如何使用收集器实现初始化1到多个关系?

1 个答案:

答案 0 :(得分:0)

您无法使用分组功能填充集合。针对每个流元素(即Helper实例)评估分组函数,以基于结果的相等来构建组。您的getBeanCgetBeanB方法每次创建一个新bean ,填充一个嵌套对象,在检查相等性后,为每个组删除其中一个对象

您的问题没有显示,如何定义这些bean的相等性,但考虑到additionalCadditionalB是唯一传递给它们的数据,我假设这些属性确定了相等。因此,在将组转换为bean实例之前,应首先按这些属性对Helper实例进行分组,即

Map<String, Map<String, List<Helper>>> tmp = helpers.stream()
    .collect(Collectors.groupingBy(Helper::getAdditionalC,
        Collectors.groupingBy(Helper::getAdditionalB)));

现在,要将它们转换为bean实例,调整工厂方法会很有帮助:

public static BeanB getBeanB(String bId, List<Helper> beanA) {
    BeanB b = new BeanB();
    b.getBeanA().addAll(beanA.stream().map(Test::getBeanA).collect(Collectors.toList()));
    b.setAdditonalB(bId);
    return b;
}

public static BeanC getBeanC(String cId, Map<String,List<Helper>> beanB) {
    BeanC c = new BeanC();
    c.getBeanB().addAll(beanB.entrySet().stream()
        .map(e -> getBeanB(e.getKey(), e.getValue()))
        .collect(Collectors.toList()));
    c.setAdditionalC(cId);
    return c;
}

getBeanA)保持不变。

然后,您可以将最终Map构建为

Map<BeanC, Map<BeanB, List<BeanA>>> res = tmp.entrySet().stream()
    .map(e -> Test.getBeanC(e.getKey(), e.getValue()))
    .collect(Collectors.toMap(Function.identity(),
        c -> c.getBeanB().stream()
              .collect(Collectors.toMap(Function.identity(), BeanB::getBeanA))));

但是,考虑到所有bean都可以通过BeanC实例访问,您很可能不需要Map,它只是分组操作的工件。因此,您只需收集到List<BeanC>代替:

List<BeanC> list = tmp.entrySet().stream()
    .map(e -> Test.getBeanC(e.getKey(), e.getValue()))
    .collect(Collectors.toList());