Why is Collectors.groupingBy confused with the identity function?

I am trying to count the integer numbers in an array using Collectors.groupingBy from the Java 8 API, but I am getting some strange compilation errors.

Here is my code:

 List<Integer> l = Arrays.asList(1, 1, 1, 2, 3, 3, 3, 3); Map<Integer, Integer> x = l.stream().collect(groupingBy(i -> i, counting())); 

Unfortunately, this does not compile, resulting in the following error:

 error: incompatible types: inferred type does not conform to equality constraint(s) Map<Integer, Integer> x = l.stream().collect(groupingBy(i -> i, counting())); ^ inferred: Integer equality constraints(s): Integer,Long 1 error 

This seems to be a problem with the generic type, because when I delete the generic map type, it compiles. Here is another test:

 List<Integer> l = Arrays.asList(1, 1, 1, 2, 3, 3, 3, 3); Map x = l.stream().collect(groupingBy(i -> i, counting())); System.out.println(x); 

And the result will be correct as expected:

 {1=3, 2=1, 3=4} 

Any ideas on how to solve this without having to drop all types here and there?

+4
source share
2 answers

If you do:

 Map<Integer, Long> x = l.stream().collect(Collectors.groupingBy(i -> i, Collectors.counting())); 

then your code will compile just fine.

The reason is that the Collectors.counting() method is defined as:

 public static <T> Collector<T, ?, Long> counting() 

Here, the third type parameter indicates the type that will be used in the BinaryOperator , which is used to calculate the counter.

Note that when you remove the type parameter for Map :

 Map x = l.stream().collect(groupingBy(i -> i, counting())); 

then the command compiles successfully, because you really work with the original version of Map , that is, the type for both keys and values ​​will be Object (which is compatible with Long , Integer and friends). However, using raw types is something to avoid, as you can annoy ClassCastException (s) at runtime.

+3
source

counting() declared as:

 static <T> Collector<T,?,Long> 

... while you are trying to use it as if it were creating an Integer .

If you change your code to:

 Map<Integer, Long> x = l.stream().collect(groupingBy(i -> i, counting())); 

... it compiles without a problem. Note that in your current code using the source type, your output actually has Long values, not Integer values ​​... it's just that you cannot say this from a string representation.

+5
source

All Articles