首页 > 解决方案 > 有条件的重制清单

问题描述

有两个实体:

class GiftCertificate {
    Long id;
    List<Tag> tags;
}

class Tag {
   Long id;
   String name;
}

有一个清单

List<GiftCertificate> 

例如,其中包含以下数据: <1, [1, "Tag1"]>, <2, null>, <1, [2, "Tag2"]>. (它不包含一组标签,但只有一个标签或根本没有它)。

我需要这样做,结果是这样的: <1, {[1," Tag1 "], [2," Tag2 "]}>, <2, null>。我的意思是,将第三个 GiftCertificate 中的标签添加到第一个对象的集合中,同时删除第三个。我想至少获得一些关于如何做到这一点的想法。使用流会很好。

标签: javacollectionsjava-8java-stream

解决方案


Java 9 引入flatMapping了特别适合此类问题的收集器。将任务分为两个步骤。首先,构建一张礼券 ID 到标签列表的映射,然后组装一个新的GiftCertificate对象列表:

import static java.util.stream.Collectors.flatMapping;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
......

Map<Long, List<Tag>> gcIdToTags = gcs.stream()
    .collect(groupingBy(
        GiftCertificate::getId,
        flatMapping(
            gc -> gc.getTags() == null ? Stream.empty() : gc.getTags().stream(),
            toList()
        )
    ));

List<GiftCertificate> r = gcIdToTags.entrySet().stream()
    .map(e -> new GiftCertificate(e.getKey(), e.getValue()))
    .collect(toList());

这假设GiftCertificate有一个接受Long idList<Tag> tags

null请注意,此代码通过创建一个空列表而不是在没有礼券 ID 的标签的情况下偏离您的要求。使用null而不是空列表只是一个非常糟糕的设计,并迫使你null到处检查来污染你的代码。

的第一个参数flatMapping也可以写成 gc -> Stream.ofNullable(gc.getTags()).flatMap(List::stream)你觉得它更具可读性。


推荐阅读