通过下游收集器进行分区产生了意外结果

问题描述

我有一个测试程序:

public class App {

    public static void main(String[] args) {

        List<Integer> a = Arrays.asList(1,11);
        List<Integer> b = Arrays.asList(2,22);
        List<Integer> c = Arrays.asList(3,33);

        Map<String,List<Integer>> map = new HashMap<>();
        map.put("a",a);
        map.put("b",b);
        map.put("c",c);

        Set<String> valid = new HashSet<>();
        valid.add("a");

        Map<Boolean,List<Map.Entry<String,List<Integer>>>> partitions =
            map.entrySet().stream()
                .collect(Collectors.partitioningBy(
                    entry -> valid.contains(entry.getKey())));

        System.out.println(partitions);

        // partition by the key of the map
        // then reduce the values into a single collection

        Map<Boolean,List<Integer>> result = map.entrySet().stream()
            .collect(Collectors.partitioningBy(
                entry -> valid.contains(entry.getKey()),Collectors.mapping(Map.Entry::getValue,Collectors.reducing(new ArrayList<>(),(l1,l2) -> {
                                                           l1.addAll(l2);
                                                           return l1;
                                                       }))));

        System.out.println(result);
    }
}

我希望最终结果是

{false=[b=[2,22],c=[3,33]],true=[a=[1,11]]}
{false=[2,22,3,33],true=[1,11]}

但是在实际结果中,true和false键都具有全部6个整数:

{false=[b=[2,11]]}
{false=[1,11,2,33]}

请注意,两个分区功能完全相同。但是下游混合了单独分区中的值。这个怎么可能?我认为下游只会在每个分区上运行...

我在这里想念什么?

谢谢。

解决方法

为减少相同的ArrayList引用,在两个分区中均使用。 您可以使用Collectors.toMap并创建一个合并两个列表的新实例。

Map<Boolean,List<Integer>> result = 
        map.entrySet()
        .stream()
        .collect(Collectors.toMap(e -> valid.contains(e.getKey()),Map.Entry::getValue,(l1,l2) -> {
          List<Integer> l3 = new ArrayList<>(l1);
          l3.addAll(l2);
          return l3;
        }));

如果您想使用相同的口味

Map<Boolean,List<Integer>> result = 
        map.entrySet()
        .stream()
        .collect(Collectors.toMap(e-> valid.contains(e.getKey()),l2) -> Stream.concat(l1.stream(),l2.stream())
                              .collect(Collectors.toList())));
,

要完成already accepted answer,您可以将Collectors.groupingByCollectors.flatMapping一起使用分类器,从Java 9开始作为下游收集器。

Map<Boolean,List<Integer>> result = map.entrySet().stream()
    .collect(Collectors.groupingBy(
         e -> valid.contains(e.getKey()),Collectors.flatMapping(e -> e.getValue().stream(),Collectors.toList())));

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...