217

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

请参阅此代码(注意:我确实知道此代码不会“工作”并且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());

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

那么,为什么要编译呢?

4

5 回答 5

243

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

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

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

答案在于新的 lambda 功能在 Java 8 中的工作方式。它依赖于一个非正式地称为“单一抽象方法”接口或“SAM”接口的概念。这个想法是任何具有一个抽象方法的接口都可以由任何 lambda - 或方法引用 - 其方法签名与接口上的一个方法匹配。所以检查Comparator界面(简单版):

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

如果一个方法正在寻找 a Comparator<Integer>,那么它本质上是在寻找这个签名:

int xxx(Integer o1, Integer o2);

我使用“xxx”是因为方法名称不用于匹配目的

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

于 2014-03-21T14:42:17.967 回答
118

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());
于 2014-03-21T14:35:23.493 回答
19

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

Integer::minresolves to Integer.min(int a, int b),resolved to和大概自动装箱的方法引用IntBinaryOperator发生在某处,使其成为BinaryOperator<Integer>.

并且请求接口的min()respmax()方法被实现。 现在这解决了单一的方法。这是类型。Stream<Integer>Comparator<Integer>
Integer compareTo(Integer o1, Integer o2)BinaryOperator<Integer>

因此魔术发生了,因为这两种方法都是BinaryOperator<Integer>.

于 2014-03-21T14:35:14.577 回答
2

除了 David M. Lloyd 提供的信息之外,还可以补充一点,允许这样做的机制称为目标类型

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

表达式的目标是分配其结果的变量或传递其结果的参数。

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

有关更多信息,请参阅 Java 教程中的类型推断部分

于 2014-04-02T10:51:40.790 回答
1

我的数组获取最大值和最小值时出错,所以我的解决方案是:

int max = Arrays.stream(arrayWithInts).max().getAsInt();
int min = Arrays.stream(arrayWithInts).min().getAsInt();
于 2018-02-19T00:56:24.260 回答