当我做一些编程练习时,偶然发现了ClassCastException
。作为背景,我给出了演示的简化版本来证明问题:
给定一个只包含字符
A
或B
的字符串,计算一个以字符为键,出现次数为值的映射。此外,地图应始终包含两个字符作为键(如果输入字符串中缺少字符,则值为零)。
示例:
"A" => {A=1, B=0}
"AAB" => {A=2, B=1}
我的第一个解决方案如下:
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
public Map<Character, Long> createResult(String input) {
Map<Character, Long> map = input.chars()
.mapToObj(c -> (char) c)
.collect(groupingBy(c -> c, counting()));
map.putIfAbsent('A', 0L);
map.putIfAbsent('B', 0L);
return map;
}
此解决方案有效,但我想尝试是否可以为groupingBy
函数提供默认值的地图:
public HashMap<Character, Long> createResult2(String input) {
return input.chars()
.mapToObj(c -> (char) c)
.collect(groupingBy(c -> c, this::mapFactory, counting()));
}
private HashMap<Character, Long> mapFactory() {
HashMap<Character, Long> map = new HashMap<>();
map.put('A', 0L);
map.put('B', 0L);
return map;
}
使用输入createResult2
调用A
时,会在运行时抛出ClassCastException
:
java.lang.ClassCastException: java.lang.Long cannot be cast to [Ljava.lang.Object; at java.util.stream.Collectors.lambda$groupingBy$45(Collectors.java:909) at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) at java.util.stream.IntPipeline$4$1.accept(IntPipeline.java:250) at java.lang.CharSequence$1CharIterator.forEachRemaining(CharSequence.java:149) at java.util.Spliterators$IntIteratorSpliterator.forEachRemaining(Spliterators.java:1908) at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
任何人都可以解释为什么会这样吗?
答案 0 :(得分:2)
涉及类型推理魔术,但如果你想要解决方案,那就是:
替换
map.put('A', 0L);
map.put('B', 0L);
通过
map.put('A', new Object[]{0L});
map.put('B', new Object[]{0L});
但我强烈反对您在实践中使用此解决方案。可以在任何更新中更改实现详细信息,并且此黑客程序停止有效。
这里有关于groupingBy
javadoc
mapFactory - 一个函数,当被调用时,会生成一个所需类型的新空Map
mapFactory
是第二个参数。单词“空”非常重要。实现使用创建的map来迭代时存储long
的数组,然后将它们转换为long
。它的作用是因为里面有大量的铸造。
答案 1 :(得分:0)
为什么不是一个简单的循环?
private static Map<Character, Integer> count(String input) {
Map<Character, Integer> result = new HashMap<>();
result.put('A', 0);
result.put('B', 0);
for (Character c : input.toCharArray()) {
result.put(c, result.get(c) + 1);
}
return result;
}