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

时间:2015-08-11 13:16:20

标签: java generics java-8

我尝试使用Java 8 API中的Collectors.groupingBy来计算数组中整数的出现次数,但我收到了一些奇怪的编译错误。

这是我的代码:

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

可悲的是,这不会编译,导致以下错误:

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

这似乎是一个泛型类型问题,因为当我删除通用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);

输出正如所料:

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

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

2 个答案:

答案 0 :(得分:5)

counting()声明为:

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

...而您正在尝试使用它,就好像它会产生Integer

如果您将代码更改为:

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

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

答案 1 :(得分:4)

如果你这样做:

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

那么你的代码就可以正常编译了。

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

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

此处,第三个类型参数表示将在BinaryOperator中用于计算计数的类型。

请注意,当您删除Map参数:

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

然后语句成功编译,因为您实际上正在使用Map的原始版本,即键和值的类型将为Object(与{{ 1}},Long和朋友们)。但是,使用原始类型是应该避免的,因为在运行时可能会令人烦恼Integer(s)。