Java 流:覆盖 return 类型的 Collectors.mapping
Java Streams: Override return type of Collectors.mapping
这是我的代码:
Map<String, Collection<? extends String>> test = listOfTipusIdentificadorPacient.stream()
.collect(Collectors.groupingBy(
TipusIdentificadorPacient::getOid,
Collectors.mapping(TipusIdentificadorPacient::getUse, Collectors.toList())
)
);
我收到这条编译消息:
Type mismatch: cannot convert from Map<String,List> to Map<String,Collection<? extends String>>
我不太明白如何覆盖 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())
)
);
有什么想法吗?
编译错误的原因是:
Map<String, List<String>> mapOfLists = Map.of();
Map<String, Collection<? extends String>> mapOfCollections = Map.of();
考虑到此代码将是合法的:
mapOfCollections.put("", Set.of());
也就是说,您可以在值不是 List<String>
的地方放置 key/value 对。因此,您不能分配:
mapOfCollections = mapOfLists;
因为那样你就可以执行上面的 put
,导致堆污染。编译器只是阻止你这样做。
// If it were legal...
mapOfCollections = mapOfLists;
mapOfCollections.put("", Set.of());
List<String> list = mapOfLists.get(""); // ClassCastException!
我认为您可以在 toList()
周围使用 Collectors.collectingAndThen
来做到这一点,其中“然后”是一个不受约束的转换:
Collectors.collectingAndThen(Collectors.toList(), a -> a)
您不能使用 Function.identity()
执行此操作的原因是 collectingAndThen
和 Function.identity()
的签名组合:
collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)
表示函数的输入类型必须与收集器的输出类型匹配 - 在您的情况下,List<String>
.
Function.identity()
是 Function<T, T>
(没有通配符)。由于函数的输入类型必须是List<String>
,它的输出类型也是List<String>
.
a -> a
看起来像恒等函数,但实际上比它更通用:它是一个向上转换函数,Function<? extends T, T>
,意味着输出类型不必须与输入完全相同,但可以安全地进行转换。
因此,在这里,a -> a
充当Function<List<String>, Collection<? extends String>>
(因为List<String>
是Collection<String>
的子类型,而Collection<? extends String>
是Collection<? extends String>
的子类型) .
这是我的代码:
Map<String, Collection<? extends String>> test = listOfTipusIdentificadorPacient.stream()
.collect(Collectors.groupingBy(
TipusIdentificadorPacient::getOid,
Collectors.mapping(TipusIdentificadorPacient::getUse, Collectors.toList())
)
);
我收到这条编译消息:
Type mismatch: cannot convert from Map<String,List> to Map<String,Collection<? extends String>>
我不太明白如何覆盖 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())
)
);
有什么想法吗?
编译错误的原因是:
Map<String, List<String>> mapOfLists = Map.of();
Map<String, Collection<? extends String>> mapOfCollections = Map.of();
考虑到此代码将是合法的:
mapOfCollections.put("", Set.of());
也就是说,您可以在值不是 List<String>
的地方放置 key/value 对。因此,您不能分配:
mapOfCollections = mapOfLists;
因为那样你就可以执行上面的 put
,导致堆污染。编译器只是阻止你这样做。
// If it were legal...
mapOfCollections = mapOfLists;
mapOfCollections.put("", Set.of());
List<String> list = mapOfLists.get(""); // ClassCastException!
我认为您可以在 toList()
周围使用 Collectors.collectingAndThen
来做到这一点,其中“然后”是一个不受约束的转换:
Collectors.collectingAndThen(Collectors.toList(), a -> a)
您不能使用 Function.identity()
执行此操作的原因是 collectingAndThen
和 Function.identity()
的签名组合:
collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)
表示函数的输入类型必须与收集器的输出类型匹配 - 在您的情况下,List<String>
.Function.identity()
是Function<T, T>
(没有通配符)。由于函数的输入类型必须是List<String>
,它的输出类型也是List<String>
.
a -> a
看起来像恒等函数,但实际上比它更通用:它是一个向上转换函数,Function<? extends T, T>
,意味着输出类型不必须与输入完全相同,但可以安全地进行转换。
因此,在这里,a -> a
充当Function<List<String>, Collection<? extends String>>
(因为List<String>
是Collection<String>
的子类型,而Collection<? extends String>
是Collection<? extends String>
的子类型) .