首页 > 解决方案 > Java Streams:覆盖 Collectors.mapping 的返回类型

问题描述

这是我的代码:

Map<String, Collection<? extends String>> test = listOfTipusIdentificadorPacient.stream()
    .collect(Collectors.groupingBy(
        TipusIdentificadorPacient::getOid,
        Collectors.mapping(TipusIdentificadorPacient::getUse, Collectors.toList())
    )
);

我收到此编译消息:

类型不匹配:无法从 Map<String,List> 转换为 Map<String,Collection<? 扩展字符串>>

我不太清楚如何覆盖Collectors.mapping以便:

return:
  Map<String,Collection<? extends String>>
instead of:
  Map<String,List<String>>

我试图创建另一个通用代码以使其能够编译。

代码是:

Stream<Map.Entry<String, String>> streamOfPairedStrings = Stream.of();
Map<String, Collection<? extends String>> test = streamOfPairedStrings
    .collect(Collectors.groupingBy(
        Map.Entry::getKey,
        Collectors.mapping(Pair::getValue, Collectors.toList())
    )
);

有任何想法吗?

标签: javajava-stream

解决方案


编译错误的原因是:

Map<String, List<String>> mapOfLists = Map.of();
Map<String, Collection<? extends String>> mapOfCollections = Map.of();

考虑到这段代码是合法的:

mapOfCollections.put("", Set.of());

也就是说,您可以将键/值对放在值不是 a 的地方List<String>。因此,您不能分配:

mapOfCollections = mapOfLists;

因为那样你就可以做put上面的事情,导致堆污染。编译器只是阻止你这样做。

// If it were legal...
mapOfCollections = mapOfLists;
mapOfCollections.put("", Set.of());
List<String> list = mapOfLists.get(""); // ClassCastException!

我认为您可以在Collectors.collectingAndThen周围执行此操作toList(),其中“然后”是不受约束的演员表:

Collectors.collectingAndThen(Collectors.toList(), a -> a)

你不能这样做的原因是和Function.identity()的签名的组合:collectingAndThenFunction.identity()

  • collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)意味着函数的输入类型必须与收集器的输出类型匹配 - 在您的情况下,List<String>.
  • Function.identity()是 a Function<T, T>(没有通配符)。由于函数的输入类型必须是List<String>,它的输出类型也是List<String>

a -> a 看起来像恒等函数,但实际上比这更通用:它是一个向上转换函数,Function<? extends T, T>这意味着输出类型不必与输入完全相同,但它是可以安全转换的东西。

因此,在这里,a -> a充当 a Function<List<String>, Collection<? extends String>>(因为List<String>是 的子类型Collection<String>,它是 的子类型Collection<? extends String>)。


推荐阅读