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

注:这个问题来自一个死链接,这是一个以前的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()); 

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

那么,为什么这个编译呢?

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

首先, Stream.max()接受Comparator一个实例,以便stream中的项目可以相互比较以find最小值或最大值,按照某种最佳顺序,您不必过多担心。

所以问题是,为什么Integer::max被接受? 毕竟这不是一个比较!

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

 public Comparator<T> { int 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>

Comparator是一个function接口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()); 

这是因为Integer::minparsing为Comparator<Integer>接口的实现。

Integer::min的方法引用parsing为Integer.min(int a, int b) ,parsing为IntBinaryOperator ,推测自动装箱发生在某个地方使其成为BinaryOperator<Integer>

Stream<Integer>min() resp max()方法要求实现Comparator<Integer>接口。
现在,这解决了单个方法Integer compareTo(Integer o1, Integer o2) 。 哪个types是BinaryOperator<Integer>

因此,这两个方法都是BinaryOperator<Integer>

除了David M. Lloyd给出的信息之外,可以补充说的是允许这个的机制被称为目标types

这个想法是,编译器赋给一个lambdaexpression式或一个方法引用的types不仅仅取决于expression式本身,还取决于它的使用位置。

expression式的目标是分配其结果的variables或其结果被传递给的参数。

如果可以find这种types,则可以为Lambdaexpression式和方法引用分配一个与其目标types相匹配的types。

有关更多信息,请参阅Java教程中的Type Inference部分 。