While I was doing a little programming exercise i stumbled upon a ClassCastException. As background i'm giving a simplified version of the exercise to demonstrate the problem:
Given a string which contains only the characters
AorBcompute 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).
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:
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:
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?