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 get converted to IntBinaryOperator
?
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)
::
is called Method Reference. It is basically a reference to a single method. I.e. it refers to an existing method by name.Short Explanation:
Below is an example of a reference to a static method:
square
can be passed around just like object references and triggered when needed. In fact, it can be just as easily used as a reference to "normal" methods of objects asstatic
ones. For example:Function
above is a functional interface. To fully understand::
, it is important to understand functional interfaces as well. Plainly, a functional interface is an interface with just one abstract method.Examples of functional interfaces include
Runnable
,Callable
, andActionListener
.Function
above is a functional interface with just one method:apply
. It takes one argument and produces a result.The reason why
::
s are awesome is that:E.g. instead of writing the lambda body
You can simply do
At runtime, these two
square
methods behave exactly the same as each other. The bytecode may or may not be the same (though, for the above case, the same bytecode is generated; compile the above and check withjavap -c
).The only major criterion to satisfy is: the method you provide should have a similar signature to the method of the functional interface you use as object reference.
The below is illegal:
square
expects an argument and returns adouble
. Theget
method in Supplier expects an argument but doesn't return anything. Thus, this results in an error.A method reference refers to the method of a functional interface. (As mentioned, functional interfaces can have only one method each).
Some more examples: the
accept
method in Consumer takes an input but doesn't return anything.Above,
getRandom
takes no argument and returns adouble
. So any functional interface that satisfies the criteria of: take no argument and returndouble
can be used.Another example:
In case of parameterized types:
Method references can have different styles, but fundamentally they all mean the same thing and can simply be visualized as lambdas:
ClassName::methName
)instanceRef::methName
)super::methName
)ClassName::methName
)ClassName::new
)TypeName[]::new
)For further reference, see http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html.
The :: is known as method references. Lets say we want to call a calculatePrice method of class Purchase. Then we can write it as:
It can also be seen as short form of writing the lambda expression Because method references are converted into lambda expressions.
:: Operator was introduced in java 8 for method references. A method reference is the shorthand syntax for a lambda expression that executes just ONE method. Here's the general syntax of a method reference:
We know that we can use lambda expressions instead of using an anonymous class. But sometimes, the lambda expression is really just a call to some method, for example:
To make the code clearer, you can turn that lambda expression into a method reference:
Yes, that is true. The
::
operator is used for method referencing. So, one can extract static methods from classes by using it or methods from objects. The same operator can be used even for constructors. All cases mentioned here are exemplified in the code sample below.The official documentation from Oracle can be found here.
You can have a better overview of the JDK 8 changes in this article. In the Method/Constructor referencing section a code example is also provided:
In older Java versions, instead of "::" or lambd, you can use:
Or passing to the method: