java - 在分组依据中使用自定义 map 供应商时出现 ClassCastException

标签 java java-8 java-stream

当我在做一些小的编程练习时,我偶然发现了一个 ClassCastException。作为背景,我给出了一个简化版本的练习来演示问题:

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. Additionally the map should always contain both characters as key (with value zero if a character is missing in the input string).

例子:

  • "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 函数提供具有默认值的 map :

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

当使用输入 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)

谁能解释为什么会这样?

最佳答案

这里涉及到类型推断魔法,但如果你想在这里找到解决方案,那就是:

替换

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

通过

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

但是我强烈反对您在实践中使用这个解决方案。可以在任何更新中更改实现细节,并且此 hack stop 有效。

这里有关于 groupingBy javadoc 中关于“为什么”的更多解释

mapFactory - a function which, when called, produces a new empty Map of the desired type

mapFactory 是第二个参数。 “空”字很重要。实现使用创建的映射在迭代时存储 long 数组,然后将它们转换为 long。它之所以有效,是因为内部有大量铸件。

关于java - 在分组依据中使用自定义 map 供应商时出现 ClassCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40386197/

相关文章:

java - Maven : Deploy Local Project to Remote Server with dependencies

Java 8 - 切换窗口后丢失所有键盘输入或焦点

java - Java8-Streams 中的 GroupingBy

java - 从列表生成列表

java - 检查字符串数组是否包含没有循环的子字符串

java - MQJE001 : Completion Code '2' , 原因'2495

视频末尾的 Java .mp4 流损坏 - 网络错误

java - 如何避免在 java 8 中使用接口(interface)?

java - 使用java中的startsWith方法删除LinkedList元素

java - 使用日期参数计算工作日