为什么Collectors.groupingBy与身份功能混淆?

Chi*_*kol 4 java generics java-8

我正在尝试使用Collectors.groupingByJava 8 API 计算数组中整数的出现次数,但是我遇到了一些奇怪的编译错误.

这是我的代码:

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

遗憾的是,这将无法编译,导致以下错误:

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
Run Code Online (Sandbox Code Playgroud)

它似乎是一个泛型类型的问题,因为当我删除通用的Map类型时,它会编译.这是另一个测试:

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);
Run Code Online (Sandbox Code Playgroud)

输出正如所料:

{1=3, 2=1, 3=4}
Run Code Online (Sandbox Code Playgroud)

如何解决这个问题的想法,而不需要在这里和那里铸造所有类型?

Kon*_*kov 6

如果你这样做:

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

那么你的代码将编译得很好。

原因是该Collectors.counting()方法定义为:

public static <T> Collector<T, ?, Long> counting()
Run Code Online (Sandbox Code Playgroud)

这里,第三个类型参数表示将BinaryOperator用于计算计数的类型。

请注意,当您删除 的类型参数时Map

Map x = l.stream().collect(groupingBy(i -> i, counting()));
Run Code Online (Sandbox Code Playgroud)

然后该语句成功编译,因为您实际上正在使用 的原始版本Map,即键和值的类型将为Object(与LongInteger和朋友兼容)。但是,应该避免使用原始类型,因为您可能会ClassCastException在运行时变得烦人。


Jon*_*eet 5

counting() 声明为:

static <T> Collector<T,?,Long>
Run Code Online (Sandbox Code Playgroud)

...而你正试图使用​​它,好像它产生了一样Integer.

如果您将代码更改为:

Map<Integer, Long> x = l.stream().collect(groupingBy(i -> i, counting()));
Run Code Online (Sandbox Code Playgroud)

...它将编译没有问题.请注意,在使用原始类型的当前代码中,您的输出实际上具有Long值而不是Integer值...它只是您无法从字符串表示中得知.