一尘不染

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

java

注意:这个问题源自于先前的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());

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

那么,为什么要编译呢?


阅读 712

收藏
2020-03-23

共2个答案

一尘不染

让我解释一下这里发生的事情,因为它并不明显!

首先,Stream.max()接受的一个实例,Comparator以便可以将流中的项目彼此进行比较,从而以不需要担心太多的最佳顺序来找到最小值或最大值。

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

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

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

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

int xxx(Integer o1, Integer o2);

我使用“ xxx”,因为方法名称未用于匹配目的。

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

2020-03-23
一尘不染

Comparator是一个功能性接口,并且Integer::max与该接口兼容(考虑了自动装箱/拆箱后)。它采用两个int值并返回int-就像你期望的那样Comparator<Integer>(再次,斜视忽略了Integer / int的差异)。

不过,我不希望它做正确的事情,因为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());
2020-03-23