我在研究Java 8源代码时,发现这部分代码非常令人惊讶:
// Defined in IntPipeline.java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
return evaluate(ReduceOps.makeInt(op));
}
@Override
public final OptionalInt max() {
return reduce(Math::max); // This is the gotcha line
}
// Defined in Math.java
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
max是一个方法指针吗?一个正常的静态方法如何转换为IntBinaryOperator?
我发现这个来源非常有趣。
事实上,是lambda变成了双冒号。双冒号可读性更好。
我们遵循以下步骤:
步骤1
// We create a comparator of two persons
Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());
步骤2
// We use the interference
Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());
步骤3
// The magic using method reference
Comparator c = Comparator.comparing(Person::getAge);
通常,我们会使用Math调用reduce方法。Max (int, int)如下:
reduce(new IntBinaryOperator() {
int applyAsInt(int left, int right) {
return Math.max(left, right);
}
});
这需要大量的语法来调用Math.max。这就是lambda表达式发挥作用的地方。因为Java 8允许它以更短的方式做同样的事情:
reduce((int left, int right) -> Math.max(left, right));
这是如何工作的呢?java编译器“检测”到你想要实现一个接受两个int型并返回一个int型的方法。这等价于接口IntBinaryOperator的唯一方法的形式参数(要调用的方法reduce的参数)。所以编译器会帮你完成剩下的工作——它只是假设你想要实现IntBinaryOperator。
但作为数学。max(int, int)本身满足IntBinaryOperator的形式要求,它可以直接使用。因为Java 7没有任何允许方法本身作为参数传递的语法(你只能传递方法结果,但不能传递方法引用),所以Java 8引入了::语法来引用方法:
reduce(Math::max);
注意,这将由编译器解释,而不是由JVM在运行时解释!虽然它为所有三个代码段生成了不同的字节码,但它们在语义上是相等的,因此后两个可以被认为是上面IntBinaryOperator实现的简短(而且可能更有效)版本!
(参见Lambda表达式的翻译)