流,使用Java 8 forEach创建列表列表(嵌套列表)

时间:2018-12-14 20:11:35

标签: java java-8 java-stream nested-lists

{
    test: /\.svg$/,
    loader: 'svg-inline-loader'
}

现在使用流,我想像这样填充:

class EntityCompositeId {
    private Long firstId;
    private Long secondId;
    // getter & setter...
}

class EntityComposite {
    private EntityCompositeId id;
    private String first;
    private String second;
    // getter & setter...
}

List<EntityComposite> listEntityComposite = ....
Supose this content

1, 1, "firstA", "secondBirdOne"
1, 2, "firstA", "secondBirdTwo"
1, 3, "firstA", "secondBirdThree"

2, 1, "firstB", "secondCatOne"
2, 2, "firstB", "secondCatTwo"
2, 3, "firstB", "secondCatThree"

3, 1, "firstC", "secondDogOne"
3, 2, "firstC", "secondDogTwo"
3, 3, "firstC", "secondDogThree"

Map<Long, List<String>> listOfLists = new HashMap<>();

我未完成的(这就是问题)代码是:

 1 -> {"secondBirdOne", "secondBirdTwo", "secondBirdThree"}
 2 -> {"secondCatOne", "secondCatTwo", "secondCatThree"}
 3 -> {"secondDogOne", "secondDogTwo", "secondDogThree"}

3 个答案:

答案 0 :(得分:10)

collectMap更适合用于生成输出forEach的终端操作。

您可以将collect()Collectors.groupingBy一起使用:

Map<Long, List<String>> listOfLists =
    listEntityComposite.stream()
                       .collect(Collectors.groupingBy(e -> e.getId().getFirstId(),
                                                      Collectors.mapping(EntityComposite::getSecond,
                                                                         Collectors.toList());

Collectors.groupingBy只有一个参数(仅e -> e.getId().getFirstId())将生成Map<Long,List<EntityComposite>>

根据需要绑定到Collectors.mapping(),将每个EntityComposite实例映射到相应的getSecond() String

答案 1 :(得分:9)

您可以通过几种不同的方法来完成手头的任务。

forEach + computeIfAbsent

 Map<Long, List<String>> map = new HashMap<>();
 listEntityComposite.forEach(e -> map.computeIfAbsent(e.getId().getFirstId(), 
                k -> new ArrayList<>()).add(e.getSecond()));
  • 通过listEntityComposite枚举forEach中的元素
  • 对于每个元素,利用computeIfAbsent来计算键(即firstId)和值(即List<String>

groupingBy + mapping

另一种方法是将groupingBymapping下游收集器一起应用:

Map<Long, List<String>> resultSet = listEntityComposite.stream()
                .collect(groupingBy(e -> e.getId().getFirstId(),
                        mapping(EntityComposite::getSecond, toList())));
  • 通过分类函数e.getId().getFirstId()对源元素进行分组,然后应用mapping下游收集器进一步优化查询。

forEach + merge

listEntityComposite.forEach(e -> map.merge(e.getId().getFirstId(),
                new ArrayList<>(singletonList(e.getSecond())),
                (l, r) -> {l.addAll(r); return l;}));
  • 通过listEntityComposite

    枚举forEach中的元素
  • 每个元素都使用merge来计算键(即firstId)和值(即List<String>

toMap

listEntityComposite.stream()
                   .collect(toMap(e -> e.getId().getFirstId(), 
                             v ->  new ArrayList<>(singletonList(v.getSecond())),
                             (l, r) -> {l.addAll(r); return l;}));
  • 应用keyMapper函数e -> e.getId().getFirstId()提取地图键。
  • 应用valueMapper函数v -> new ArrayList<>(singletonList(v.getSecond()))提取地图值。
  • 应用merge函数(l, r) -> {l.addAll(r); return l;}解决键冲突。

总而言之,在这种特定情况下,forEach + computeIfAbsent方法和groupingBy + mapping方法是您应该偏爱的两种方法,因为它们比较惯用

答案 2 :(得分:0)

我建议研究一下Guava的MultiMap,它使您的用例更易于处理(提供了很多优化和更多功能,您可能以后会希望获得这些功能)

编辑: 例如,为什么使用Multimap比使用computeIfAbsent方法更有意义的示例:  1.每个密钥都有一个特定大小的列表,如果将来您希望获得“总”大小怎么办?您将必须创建一些逻辑以实现良好的性能(或使用采用O(keys)的方法)  2.目前,您只是将事物放入地图中,但是如果您将来想从地图中删除事物,会发生什么?您将需要编写一些样板代码(很容易出错),以确保删除值不会导致内存泄漏

使用多图还有其他好处,但这只是两个易于解释的好处。

编辑2: 使用您的输入的示例:

import java.util.Arrays;
import java.util.List;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;

public class Example {

    public static class EntityCompositeId {
        @Override
        public String toString() {
            return "EntityCompositeId [firstId=" + firstId + ", secondId=" + secondId + "]";
        }

        public EntityCompositeId(Long firstId, Long secondId) {
            super();
            this.firstId = firstId;
            this.secondId = secondId;
        }

        private Long firstId;

        public Long getFirstId() {
            return firstId;
        }

        private Long secondId;
    }

    public static class EntityComposite {
        @Override
        public String toString() {
            return "EntityComposite [id=" + id + ", first=" + first + ", second=" + second + "]";
        }

        public EntityComposite(EntityCompositeId id, String first, String second) {
            super();
            this.id = id;
            this.first = first;
            this.second = second;
        }

        private EntityCompositeId id;

        public EntityCompositeId getId() {
            return id;
        }

        private String first;
        private String second;
    }

    public static void main(String[] args) {
        List<EntityComposite> listEntityComposite = Arrays.asList(
                new EntityComposite(new EntityCompositeId(1l, 1l), "firstA", "secondBirdOne"),
                new EntityComposite(new EntityCompositeId(1l, 2l), "firstA", "secondBirdTwo"),
                new EntityComposite(new EntityCompositeId(1l, 3l), "firstA", "secondBirdThree"),
                new EntityComposite(new EntityCompositeId(2l, 1l), "firstB", "secondCatOne"),
                new EntityComposite(new EntityCompositeId(2l, 2l), "firstB", "secondCatTwo"),
                new EntityComposite(new EntityCompositeId(2l, 3l), "firstB", "secondCatThree"),
                new EntityComposite(new EntityCompositeId(3l, 1l), "firstC", "secondDogOne"),
                new EntityComposite(new EntityCompositeId(3l, 2l), "firstC", "secondDogTwo"),
                new EntityComposite(new EntityCompositeId(3l, 3l), "firstC", "secondDogThree"));
        ListMultimap<Long, EntityComposite> map = ArrayListMultimap.create();
        listEntityComposite.forEach(entityComposite -> map.put(entityComposite.getId().getFirstId(), entityComposite));
        map.keySet().forEach(key -> System.out.println(map.get(key)));
    }
}

产生以下输出:

[EntityComposite [id=EntityCompositeId [firstId=1, secondId=1], first=firstA, second=secondBirdOne], EntityComposite [id=EntityCompositeId [firstId=1, secondId=2], first=firstA, second=secondBirdTwo], EntityComposite [id=EntityCompositeId [firstId=1, secondId=3], first=firstA, second=secondBirdThree]]
[EntityComposite [id=EntityCompositeId [firstId=2, secondId=1], first=firstB, second=secondCatOne], EntityComposite [id=EntityCompositeId [firstId=2, secondId=2], first=firstB, second=secondCatTwo], EntityComposite [id=EntityCompositeId [firstId=2, secondId=3], first=firstB, second=secondCatThree]]
[EntityComposite [id=EntityCompositeId [firstId=3, secondId=1], first=firstC, second=secondDogOne], EntityComposite [id=EntityCompositeId [firstId=3, secondId=2], first=firstC, second=secondDogTwo], EntityComposite [id=EntityCompositeId [firstId=3, secondId=3], first=firstC, second=secondDogThree]]