当前位置: 首页 > 知识库问答 >
问题:

使用java流将平面列表转换为具有子对象的域对象

邢勇
2023-03-14

我有一个平面非规范化结构的传入对象,我从JDBC结果集实例化了它。传入对象镜像结果集,有大量重复数据,因此我希望将数据转换为具有嵌套子集合的父对象列表,即对象图或规范化列表。

传入对象的类如下所示:

class IncomingFlatItem {
    String clientCode;
    String clientName;
    String emailAddress;
    boolean emailHtml;
    String reportCode;
    String reportLanguage;
}

因此,传入的数据包含每个客户机的多个对象,我想将其聚合为一个客户机对象,其中包含客户机的电子邮件地址对象列表和报表对象列表。

因此,客户端对象将如下所示:

class Client {
    String clientCode;
    String clientName;
    Set<EmailAddress> emailAddresses;
    Set<Report> reports;
}

奇怪的是,我找不到一个现有的答案。我正在寻找嵌套流或链接流,但我希望找到最优雅的方法,并且我绝对希望避免for循环。

共有3个答案

严天逸
2023-03-14

您可以使用映射函数来转换列表

Function<List<IncomingFlatItem>, Set<EmailAddress>> inferEmailAddress =
        incomingFlatItems -> incomingFlatItems.stream()
                .map(obj -> new EmailAddress(obj.getEmailAddress(), 
                                             obj.isEmailHtml()))
                .collect(Collectors.toSet());

Function<List<IncomingFlatItem>, Set<Report>> inferReports =
        incomingFlatItems -> incomingFlatItems.stream()
                .map(obj -> new Report(obj.getReportCode(), 
                                       obj.getReportLanguage()))
                .collect(Collectors.toSet());

进一步使用groupingBy并将条目映射到列表

List<Client> transformIntoGroupedNormalisedContent(
                  List<IncomingFlatItem> incomingFlatItemList) {
    return incomingFlatItemList.stream()
            .collect(Collectors.groupingBy(inc ->
                    Arrays.asList(inc.getClientCode(), inc.getClientName())))
            .entrySet()
            .stream()
            .map(e -> new Client(e.getKey().get(0), 
                                 e.getKey().get(1),
                                 inferEmailAddress.apply(e.getValue()), 
                                 inferReports.apply(e.getValue())))
            .collect(Collectors.toList());
}

杜绍元
2023-03-14

您可以做的一件事是利用构造函数参数和流畅的API。考虑“嵌套”流和流API(带有动态数据)可能会很快变得复杂。

这只是使用一个fluentapi来简化事情(您可以使用一个合适的构建器模式)

class Client {
    String clientCode;
    String clientName;
    Set<EmailAddress> emailAddresses = new HashSet<>();
    Set<Report> reports = new HashSet<>();

    public Client(String clientCode, String clientName) {
        super();
        this.clientCode = clientCode;
        this.clientName = clientName;
    }

    public Client emailAddresses(String address, boolean html) {
        this.emailAddresses = 
             Collections.singleton(new EmailAddress(address, html));
        return this;
    }

    public Client reports(String... reports) {
        this.reports = Arrays.stream(reports)
                        .map(Report::new)
                        .collect(Collectors.toSet());
        return this;
    }

    public Client merge(Client other) {
        this.emailAddresses.addAll(other.emailAddresses);
        this.reports.addAll(other.reports);

        if (null == this.clientName)
            this.clientName = other.clientName;
        if (null == this.clientCode)
            this.clientCode = other.clientCode;

        return this;
    }
}

class EmailAddress {
    public EmailAddress(String e, boolean html) {

    }
}

class Report {
    public Report(String r) {

    }
}

Collection<Client> clients = incomingFlatItemsCollection.stream()
        .map(flatItem -> new Client(flatItem.clientCode, flatItem.clientName)
                          .emailAddresses(flatItem.emailAddress, flatItem.emailHtml)
                          .reports(flatItem.reportCode, flatItem.reportLanguage))
        .collect(Collectors.groupingBy(Client::getClientCode,
                Collectors.reducing(new Client(null, null), Client::merge)))
        .values();

或者,您也可以只使用映射函数将IncomingFlatItem对象转换为客户端

徐飞龙
2023-03-14

你可以用这个:

List<Client> clients = items.stream()
        .collect(Collectors.groupingBy(i -> Arrays.asList(i.getClientCode(), i.getClientName())))
        .entrySet().stream()
        .map(e -> new Client(e.getKey().get(0), e.getKey().get(1),
                e.getValue().stream().map(i -> new EmailAddress(i.getEmailAddress(), i.isEmailHtml())).collect(Collectors.toSet()),
                e.getValue().stream().map(i -> new Report(i.getReportCode(), i.getReportLanguage())).collect(Collectors.toSet())))
        .collect(Collectors.toList());

开始时,您按clientCodeclientName对项目进行分组。然后将结果映射到客户机对象。

确保。equals()hashCode()方法用于EmailAddressReport以确保它们在集合中是不同的。

 类似资料:
  • 我有下面的pojo 此employee类用于从mybatis orm获取对象列表(list)。 mybatis将输出作为列表返回,因为mybatis不支持将Map作为返回类型 我必须把它转换成地图 我尝试了下面的方法,但没有成功,因为它需要getName()和getId()方法 请告知是否有一种方法可以在不修改员工pojo的情况下使用stream实现。 注意:我知道我们可以使用ofr或for ea

  • 问题内容: 有人知道有什么好的库可以将平面文件转换为Java对象吗?我发现了扁虫,但我正在寻找替代品。 问题答案: FFP-平面文件解析库 http://jffp.sourceforge.net/

  • 我最近开始处理Java流。我试图从我的一个SQL查询的结果集中获取字符串值。结果集只从数据库中选择一个字符串/Varchar列。 所以我做了: 或: 我相信地图具有将数据从一种类型转换为另一种类型的功能。在本例中,从对象到字符串,然后在字符串列表中收集它们。 但上面的代码显示了编译时错误:无法从对象转换为字符串列表。 请给我建议正确的做法,并说明我的理解有什么问题。

  • 问题内容: 我从服务器得到一个 json数组: 我想使用gson将上面的json数据转换为Java 对象。我尝试了以下方法: 首先,我创建了一个 Person.java 类: 然后,在服务类中,我执行了以下操作: 我收到异常 java.lang.ClassCastException:java.util.LinkedHashMap无法强制转换为Person 。如何摆脱我的问题?我只想将json数组转

  • 问题内容: 如何转换 这是例子 有没有简单的方法可以做到这一点?什么库在这里有用? 谢谢。 问题答案: 也许http://dozer.sourceforge.net可以为您提供帮助。它是可通过xml配置的映射库。 我很快尝试了这个: 我的mappings.xml看起来像这样: 不幸的是,它仅将10映射到所有三个PojoObject属性。也许您可以看到错误并使用代码段。也许这是Dozer中的一个错误