java - 收集/计数到非空 Map 会引发 ClassCastException
问题描述
我的目标是将列表中每个项目的计数存储在地图中。这可以通过groupingBy()
和counting()
方法来实现。
我的下一个约束是,对于不在 List 中的值,我仍然需要将该键映射为 0。因此必须定义所有可能的值。
这是我想出的:
Map<String, Long> EMPTY = Map.of("a", 0L,
"b", 0L,
"c", 0L,
"d", 0L);
List<String> list = List.of("a", "a", "d", "c", "d", "c", "a", "d");
Map<String, Long> count = list.stream()
.collect(groupingBy(s -> s,
() -> new HashMap<>(EMPTY),
counting()));
此代码引发以下异常:
Exception in thread "main" java.lang.ClassCastException: class java.lang.Long cannot be cast to class [J (java.lang.Long and [J are in module java.base of loader 'bootstrap')
at java.base/java.util.stream.Collectors.lambda$groupingBy$53(Collectors.java:1129)
at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at Test.main(Test.java:18)
但是,如果我只是new HashMap<>(EMPTY)
用new HashMap<>()
代码替换就可以了。
我在收集过程中不使用空地图是否违反了某些规定?否则我将如何使用流实现我的目标?
解决方案
这是一个有点奇怪的错误。具体来说,您正在使用的收集器(通过 using Collectors.counting
)实际上正在累积到原始long
s 的单个元素数组中。
public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper)
{
return new CollectorImpl<>(
() -> new long[1],
(a, t) -> { a[0] += mapper.applyAsLong(t); },
(a, b) -> { a[0] += b[0]; return a; },
a -> a[0], CH_NOID);
}
什么groupingBy
时候 a computeIfAbsent
,它期望得到 along[]
但是因为你已经有一个“a”的密钥,你得到的 aLong
与累加器接受的类型不匹配。这就是引发异常的原因。
A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
downstreamAccumulator.accept(container, t);
稍后,它们会替换所有地图值:
intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
使用上面定义的 'finisher' ( a -> a[0]
) 从long[]
s 到Long
s。
是的,有点淘气,但你违反了合同
mapFactory:供应商提供一个新的空地图,结果将插入其中
所以这也很公平。他们正在采用HashMap
which 在编译时被决定为Map<String, Long>
并且他们正在将long[]
s 放入其中。这是可能的,因为泛型没有具体化。在运行时,它只是HashMap
能够存储任何类型的键和值。
推荐阅读
- xml - 双换栏问题
- python - 我可以让生成器中的第一个元素返回一些特殊/不同的东西吗?
- django - 在序列化程序 DRF 中创建 api 之前编写 if else 逻辑
- django - Django - 基于嵌套对象聚合分数
- flutter - Flutter - 可滚动视图内的 TabView
- python - 为什么我的 python 客户端在从 Internet 接收数据时挂起?
- java - 如何在 Android Studio 中将日期选择器对话框值转换为字符串,如(2021 年 1 月 13 日)?
- java - 后缀转换器中的中缀符号错误
- docusignapi - C#.net docusign Api 调用返回错误(底层连接已关闭:接收时发生意外错误)
- javascript - Ajax 向 Flask 中的 D3JS 发送数据