Java 8 中的 ::(双冒号)运算符

2022-01-30 00:00:00 java-8 java

我正在探索 Java 8 源代码,发现这部分代码非常令人惊讶:

I was exploring the Java 8 source and found this particular part of code very surprising:

//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;
}

Math::max 是不是类似于方法指针?普通的 static 方法是如何转换为 IntBinaryOperator 的?

Is Math::max something like a method pointer? How does a normal static method gets converted to IntBinaryOperator?

推荐答案

通常会使用 Math.max(int, int) 调用 reduce 方法,如下所示:

Usually, one would call the reduce method using Math.max(int, int) as follows:

reduce(new IntBinaryOperator() {
    int applyAsInt(int left, int right) {
        return Math.max(left, right);
    }
});

仅调用 Math.max 就需要大量语法.这就是 lambda 表达式发挥作用的地方.从 Java 8 开始,它允许以更短的方式做同样的事情:

That requires a lot of syntax for just calling Math.max. That's where lambda expressions come into play. Since Java 8 it is allowed to do the same thing in a much shorter way:

reduce((int left, int right) -> Math.max(left, right));

这是如何工作的?Java 编译器检测到"您想要实现一个接受两个 int 并返回一个 int 的方法.这相当于接口IntBinaryOperator的唯一方法的形参(你要调用的方法reduce的参数).所以编译器会为你完成剩下的工作——它只是假设你想要实现 IntBinaryOperator.

How does this work? The java compiler "detects", that you want to implement a method that accepts two ints and returns one int. This is equivalent to the formal parameters of the one and only method of interface IntBinaryOperator (the parameter of method reduce you want to call). So the compiler does the rest for you - it just assumes you want to implement IntBinaryOperator.

但是由于Math.max(int, int)本身就满足IntBinaryOperator的形式要求,所以可以直接使用.因为 Java 7 没有任何语法允许将方法本身作为参数传递(您只能传递方法结果,但不能传递方法引用),Java 8 中引入了 :: 语法参考方法:

But as Math.max(int, int) itself fulfills the formal requirements of IntBinaryOperator, it can be used directly. Because Java 7 does not have any syntax that allows a method itself to be passed as an argument (you can only pass method results, but never method references), the :: syntax was introduced in Java 8 to reference methods:

reduce(Math::max);

请注意,这将由编译器解释,而不是在运行时由 JVM 解释!尽管它为所有三个代码片段生成不同的字节码,但它们在语义上是相等的,因此最后两个可以被认为是上述 IntBinaryOperator 实现的简短(并且可能更有效)版本!

Note that this will be interpreted by the compiler, not by the JVM at runtime! Although it produces different bytecodes for all three code snippets, they are semantically equal, so the last two can be considered to be short (and probably more efficient) versions of the IntBinaryOperator implementation above!

(另请参见Lambda 表达式的翻译)

相关文章