注意:这个问题源于一个死链接,这是以前的SO问题,但是这里......
请参阅此代码( note: I do know that this code won't "work" and that Integer::compare should be used -- I just extracted it from the linked question ):
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 回答
让我解释一下这里发生了什么,因为它并不明显!
首先,Stream.max()接受Comparator的实例,以便可以将流中的项目相互比较以找到最小值或最大值,以一些您不需要过多担心的最佳顺序 .
所以问题是,为什么Integer::max被接受了?毕竟它不是比较器!
答案就在于新的lambda功能在Java 8中的工作方式 . 它依赖于一个非正式地称为"single abstract method"接口或"SAM"接口的概念 . 这个想法是任何带有一个抽象方法的接口都可以通过任何lambda或方法引用自动实现 - 其方法签名与接口上的一个方法匹配 . 所以检查Comparator接口(简单版本):
如果某个方法正在寻找
Comparator<Integer>
,那么它实际上是在寻找这个签名:我用"xxx" because the method name is not used for matching purposes .
因此,
Integer.min(int a, int b)
和_566114都足够接近自动装箱将允许它在方法上下文中显示为Comparator<Integer>
.Comparator
是一个功能接口,Integer::max
符合该接口(考虑自动装箱/拆箱后) . 它需要两个int
值并返回int
- 就像你期望Comparator<Integer>
一样(再次,斜视忽略Integer / int差异) .但是,鉴于
Integer.max
不符合Comparator.compare
的语义,我不希望它做正确的事情 . 事实上,它确实不起作用 . 例如,做一个小改动:...现在
max
值为-20,min
值为-1 .相反,两个调用都应该使用
Integer::compare
:这是有效的,因为
Integer::min
解析为Comparator<Integer>
接口的实现 .Integer::min
的方法参考解析为Integer.min(int a, int b)
,解析为IntBinaryOperator
,并且可能在某处使自动装箱成为BinaryOperator<Integer>
.并且
Stream<Integer>
的min()
respmax()
方法要求实现Comparator<Integer>
接口 .现在这解析为单个方法
Integer compareTo(Integer o1, Integer o2)
. 哪个是BinaryOperator<Integer>
类型 .因此,两种方法都是
BinaryOperator<Integer>
,因此发生了魔法 .除了David M. Lloyd提供的信息之外,可以补充说,允许这种情况的机制称为目标类型 .
我们的想法是编译器分配给lambda表达式或方法引用的类型不仅取决于表达式本身,还取决于它的使用位置 .
表达式的目标是分配其结果的变量或其结果传递到的参数 .
如果可以找到这样的类型,则为Lambda表达式和方法引用分配与其目标类型匹配的类型 .
有关更多信息,请参阅Java教程中的Type Inference section .
我有一个错误,数组得到最大和最小,所以我的解决方案是: