Java 8流的.min()和.max():为什么要编译?

时间:2014-03-21 14:31:14

标签: java java-8 java-stream

注意:这个问题源于一个死链接,这是一个先前的SO问题,但这里有......

请参阅此代码(注意:我确实知道此代码已赢得'#34;工作"应使用Integer::compare - 我只是从链接中提取它问题):

final ArrayList <Integer> list 
    = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());

System.out.println(list.stream().max(Integer::max).get());
System.out.println(list.stream().min(Integer::min).get());

根据.min().max()的javadoc,两者的参数应为Comparator。然而,这里的方法引用是Integer类的静态方法。

那么,为什么要编译呢?

5 个答案:

答案 0 :(得分:239)

让我解释一下这里发生了什么,因为它并不明显!

首先,Stream.max()接受Comparator的实例,以便可以将流中的项目相互比较以找到最小值或最大值,以您不需要的最佳顺序太担心了。

所以问题是,为什么Integer::max被接受了?毕竟它不是比较器!

答案在于新的lambda功能在Java 8中的工作方式。它依赖于一种非正式地称为&#34;单一抽象方法&#34;接口,或&#34; SAM&#34;接口。这个想法是任何带有一个抽象方法的接口都可以通过任何lambda或方法引用自动实现 - 其方法签名与接口上的一个方法匹配。所以检查Comparator接口(简单版本):

public Comparator<T> {
    T compare(T o1, T o2);
}

如果某个方法正在寻找Comparator<Integer>,那么它本质上正在寻找此签名:

int xxx(Integer o1, Integer o2);

我用&#34; xxx&#34; 因为方法名称不用于匹配目的

因此,Integer.min(int a, int b)Integer.max(int a, int b)都足够接近,自动装箱将允许它在方法上下文中显示为Comparator<Integer>

答案 1 :(得分:115)

Comparator功能界面Integer::max符合该界面(考虑自动装箱/取消装箱后)。它需要两个int值并返回int - 正如您期望Comparator<Integer>一样(再次,斜视以忽略整数/整数差异)。

但是,鉴于Integer.max不符合Comparator.compare语义,我不希望它做正确的事情。事实上,它确实不起作用。例如,进行一项小改动:

for (int i = 1; i <= 20; i++)
    list.add(-i);

...现在max值为-20,min值为-1。

相反,两个调用都应使用Integer::compare

System.out.println(list.stream().max(Integer::compare).get());
System.out.println(list.stream().min(Integer::compare).get());

答案 2 :(得分:19)

这是有效的,因为Integer::min解析为Comparator<Integer>接口的实现。

Integer::min的方法引用解析为Integer.min(int a, int b),已解析为IntBinaryOperator,并且可能会在某处使自动装箱成为BinaryOperator<Integer>

min()的{​​{1}} resp max()方法要求Stream<Integer>接口实施。
现在,这解析为单个方法Comparator<Integer>。其类型为Integer compareTo(Integer o1, Integer o2)

因此两种方法都是BinaryOperator<Integer>

答案 3 :(得分:2)

除了David M. Lloyd提供的信息之外,可以补充说,允许这种情况的机制称为目标类型

这个想法是编译器分配给lambda表达式或方法引用的类型不仅取决于表达式本身,还取决于它的使用位置。

表达式的目标是指定结果的变量或传递结果的参数。

如果可以找到这样的类型,则为Lambda表达式和方法引用分配一个与其目标类型匹配的类型。

有关详细信息,请参阅Java教程中的Type Inference section

答案 4 :(得分:0)

我遇到一个错误,数组得到最大值和最小值,所以我的解决方案是:

/auth