注意:这个问题源于一个死链接,这是一个先前的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
类的静态方法。
那么,为什么要编译呢?
答案 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