Java 8 流的 .min() 和 .max():为什么要编译?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22561614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8 stream's .min() and .max(): why does this compile?
提问by fge
Note: this question originates from a dead link which was a previous SO question, but here goes...
注意:这个问题来自一个死链接,这是一个以前的 SO 问题,但这里是......
See this code (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):
看到这个代码(注意:我知道这个代码不会“工作”,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());
According to the javadoc of .min()
and .max()
, the argument of both should be a Comparator
. Yet here the method references are to static methods of the Integer
class.
根据.min()
and的javadoc,.max()
两者的参数应该是 a Comparator
。然而这里的方法引用是对Integer
类的静态方法的引用。
So, why does this compile at all?
那么,为什么要编译呢?
采纳答案by David M. Lloyd
Let me explain what is happening here, because it isn't obvious!
让我解释一下这里发生了什么,因为它并不明显!
First, Stream.max()
accepts an instance of Comparator
so that items in the stream can be compared against each other to find the minimum or maximum, in some optimal order that you don't need to worry too much about.
首先,Stream.max()
接受一个实例,Comparator
以便可以将流中的项目相互比较以找到最小值或最大值,以某种您无需过多担心的最佳顺序。
So the question is, of course, why is Integer::max
accepted? After all it's not a comparator!
所以问题当然是,为什么被Integer::max
接受?毕竟不是比较器!
The answer is in the way that the new lambda functionality works in Java 8. It relies on a concept which is informally known as "single abstract method" interfaces, or "SAM" interfaces. The idea is that any interface with one abstract method can be automatically implemented by any lambda - or method reference - whose method signature is a match for the one method on the interface. So examining the Comparator
interface (simple version):
答案在于新的 lambda 功能在 Java 8 中的工作方式。它依赖于一个非正式地称为“单一抽象方法”接口或“SAM”接口的概念。这个想法是任何具有一个抽象方法的接口都可以由任何 lambda 或方法引用自动实现,其方法签名与接口上的一个方法相匹配。所以检查Comparator
界面(简单版):
public Comparator<T> {
T compare(T o1, T o2);
}
If a method is looking for a Comparator<Integer>
, then it's essentially looking for this signature:
如果一个方法正在寻找 a Comparator<Integer>
,那么它本质上是在寻找这个签名:
int xxx(Integer o1, Integer o2);
I use "xxx" because the method name is not used for matching purposes.
我使用“xxx”是因为方法名称不用于匹配目的。
Therefore, both Integer.min(int a, int b)
and Integer.max(int a, int b)
are close enough that autoboxing will allow this to appear as a Comparator<Integer>
in a method context.
因此,无论是Integer.min(int a, int b)
和Integer.max(int a, int b)
接近不够,自动装箱会允许这种情况出现的Comparator<Integer>
一个方法上下文。
回答by skiwi
This works because Integer::min
resolves to an implementation of the Comparator<Integer>
interface.
这是有效的,因为Integer::min
解析为Comparator<Integer>
接口的实现。
The method reference of Integer::min
resolves to Integer.min(int a, int b)
, resolved to IntBinaryOperator
, and presumably autoboxing occurs somewhere making it a BinaryOperator<Integer>
.
的方法引用Integer::min
解析为Integer.min(int a, int b)
,解析为IntBinaryOperator
,并且大概自动装箱发生在某处使其成为BinaryOperator<Integer>
.
And the min()
resp max()
methods of the Stream<Integer>
ask the Comparator<Integer>
interface to be implemented.
Now this resolves to the single method Integer compareTo(Integer o1, Integer o2)
. Which is of type BinaryOperator<Integer>
.
以及询问要实现的接口的min()
响应max()
方法。
现在这解析为单一方法。这是类型.Stream<Integer>
Comparator<Integer>
Integer compareTo(Integer o1, Integer o2)
BinaryOperator<Integer>
And thus the magic has happened as both methods are a BinaryOperator<Integer>
.
因此,神奇的事情发生了,因为这两种方法都是BinaryOperator<Integer>
.
回答by Jon Skeet
Comparator
is a functional interface, and Integer::max
complies with that interface (after autoboxing/unboxing is taken into consideration). It takes two int
values and returns an int
- just as you'd expect a Comparator<Integer>
to (again, squinting to ignore the Integer/int difference).
Comparator
是一个功能接口,并Integer::max
符合该接口(在考虑自动装箱/拆箱之后)。它需要两个int
值并返回一个int
- 就像您期望的那样Comparator<Integer>
(再次眯眼以忽略整数/整数差异)。
However, I wouldn't expect it to do the right thing, given that Integer.max
doesn't comply with the semanticsof Comparator.compare
. And indeed it doesn't really work in general. For example, make one small change:
不过,我不希望它做正确的事情,因为Integer.max
它不符合语义的Comparator.compare
。事实上,它在一般情况下并没有真正起作用。例如,做一个小改动:
for (int i = 1; i <= 20; i++)
list.add(-i);
... and now the max
value is -20 and the min
value is -1.
...现在max
值为-20,min
值为-1。
Instead, both calls should use Integer::compare
:
相反,两个调用都应该使用Integer::compare
:
System.out.println(list.stream().max(Integer::compare).get());
System.out.println(list.stream().min(Integer::compare).get());
回答by Lii
Apart from the information given by David M. Lloyd one could add that the mechanism that allows this is called target typing.
除了 David M. Lloyd 提供的信息之外,还可以补充一点,允许这样做的机制称为目标类型。
The idea is that the type the compiler assigns to a lambda expressions or a method references does not depend only on the expression itself, but also on where it is used.
这个想法是编译器分配给 lambda 表达式或方法引用的类型不仅取决于表达式本身,还取决于它的使用位置。
The target of an expression is the variable to which its result is assigned or the parameter to which its result is passed.
表达式的目标是为其结果分配的变量或将其结果传递给的参数。
Lambda expressions and method references are assigned a type which matches the type of their target, if such a type can be found.
Lambda 表达式和方法引用被分配一个与其目标类型相匹配的类型(如果可以找到这样的类型)。
See the Type Inference sectionin the Java Tutorial for more information.
有关更多信息,请参阅Java 教程中的类型推断部分。
回答by JPRLCol
I had an error with an array getting the max and the min so my solution was:
我在数组获取最大值和最小值时出错,所以我的解决方案是:
int max = Arrays.stream(arrayWithInts).max().getAsInt();
int min = Arrays.stream(arrayWithInts).min().getAsInt();