我的目标是在Map中存储列表中每一项的计数。这可以通过groupingBy()和counting()方法来实现。
我所拥有的下一个约束是,对于列表中没有的值,我仍然需要将该键映射为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<>(),那么代码可以正常工作。
我是否因为没有为收集过程使用空Map而违反了什么?否则,我如何使用流来实现我的目标呢?
发布于 2019-01-29 17:18:44
这是个奇怪的错误。具体来说,您使用的收集器(借助Collectors.counting)实际上正在积累到原始long的单个元素数组中。
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执行computeIfAbsent时,它希望得到一个long[],但是因为您已经有了一个"a“的键,所以返回一个Long,它与累加器所接受的类型不匹配。这就是抛出异常的原因。
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转到Longs。
是的,有点淘气,但你违反了合同
mapFactory:提供新的空映射的供应商,将结果插入其中
所以这也很公平。他们正在使用一个在编译时被确定为Map<String, Long>的Map<String, Long>,并将long[]投入其中。这是可能的,因为仿制药没有被具体化。在运行时,它只是一个能够存储任何类型的键和值的HashMap。
发布于 2019-01-29 17:18:22
正如文档为Collectors.groupingBy(classifier, mapFactory, downstream)声明的那样
参数:
发布于 2019-01-29 17:36:19
流列表,并使用groupingBy和counting将其转换为Map<String,Long>,然后在EMPTY映射中使用foreach更新值。
list.stream().collect(Collectors.groupingBy(Function.identity(),Collectors.counting()))
.forEach((k,v)->empty.put(k, v)); //java coding standards variable name should be in lower case https://stackoverflow.com/questions/54426000
复制相似问题