简体   繁体   English

在分组中使用自定义地图供应商时出现ClassCastException

[英]ClassCastException when using custom map supplier in grouping-by

While I was doing a little programming exercise i stumbled upon a ClassCastException . 当我做一些编程练习时,我偶然发现了ClassCastException As background i'm giving a simplified version of the exercise to demonstrate the problem: 作为背景我正在提供演示的简化版本来演示问题:

Given a string which contains only the characters A or B compute a map with the characters as keys and the number of occurrences as values. 给定仅包含字符AB的字符串,计算以字符为键并将出现次数作为值的映射。 Additionally the map should always contain both characters as key (with value zero if a character is missing in the input string). 此外,地图应始终包含两个字符作为键(如果输入字符串中缺少字符,则值为零)。

Examples: 例子:

  • "A" => {A=1, B=0}
  • "AAB" => {A=2, B=1}

My first solution was the following: 我的第一个解决方案如下:

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;
}

This solution worked but i wanted to try if it was possible to supply a map with default values to the groupingBy function: 这个解决方案有效,但我想试试是否有可能为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;
}

When calling createResult2 with input A a ClassCastException is thrown at runtime: 使用输入A调用createResult2 ,会在运行时抛出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)

Can anyone explain why this is happening? 任何人都可以解释为什么会这样吗?

There is type inference magic involved, but if you want solution here it is: 涉及类型推理魔术,但如果你想要解决方案,它是:

Replace 更换

map.put('A', 0L);
map.put('B', 0L);

by 通过

map.put('A', new Object[]{0L});
map.put('B', new Object[]{0L});

But I strongly discourage you of using this solution in practice . 我强烈反对你在实践中使用这个解决方案 Implementation details can be changed in any update and this hack stop works. 可以在任何更新中更改实现详细信息,并且此黑客程序停止有效。

Here more explanation about "why" from groupingBy javadoc 这里有更多关于groupingBy javadoc的“为什么”的解释

mapFactory - a function which, when called, produces a new empty Map of the desired type mapFactory - 一个函数,在调用时,会生成所需类型的新空Map

mapFactory is second parameter. mapFactory是第二个参数。 Word "empty" is very important. 单词“空”非常重要。 Implementation use created map to store arrays of long while iterating and then convert them to long . 实现使用创建的map来存储long迭代的数组,然后将它们转换为long It works because of massive amount of casting inside. 它的作用是因为里面有大量的铸造。

Why not a simple loop? 为什么不是简单的循环?

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM