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;
}
Is Math::max
something like a method pointer?
How does a normal static
method gets converted to IntBinaryOperator
?
Best Answer
Usually, one would call the
reduce
method usingMath.max(int, int)
as follows: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:How does this work? The java compiler "detects", that you want to implement a method that accepts two
int
s and returns oneint
. This is equivalent to the formal parameters of the one and only method of interfaceIntBinaryOperator
(the parameter of methodreduce
you want to call). So the compiler does the rest for you - it just assumes you want to implementIntBinaryOperator
.But as
Math.max(int, int)
itself fulfills the formal requirements ofIntBinaryOperator
, 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: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!(See also Translation of Lambda Expressions)