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
?
It seems its little late but here are my two cents. A lambda expression is used to create anonymous methods. It does nothing but call an existing method, but it is clearer to refer to the method directly by its name. And method reference enables us to do that using method-reference operator
::
.Consider the following simple class where each employee has a name and grade.
Suppose we have a list of employees returned by some method and we want to sort the employees by their grade. We know we can make use of anonymous class as:
where getDummyEmployee() is some method as:
Now we know that Comparator is a Functional Interface. A Functional Interface is the one with exactly one abstract method (though it may contain one or more default or static methods). So we can use lambda expression as:
It seems all good but what if the class
Employee
also provides similar method:In this case using the method name itself will be more clear. Hence we can directly refer to method by using method reference as:
As per docs there are four kinds of method references:
At runtime they behave a exactly the same.The bytecode may/not be same (For above Incase,it generates the same bytecode(complie above and check javaap -c;))
At runtime they behave a exactly the same.method(math::max);,it generates the same math (complie above and check javap -c;))
This is a method reference in Java 8. The oracle documentation is here.
As stated in the documentation...
So I see here tons of answers that are frankly overcomplicated, and that's an understatement.
The answer is pretty simple: :: it's called a Method References https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
So I won't copy-paste, on the link, you can find all the information if you scroll down to the table.
Now, let's take a short look at what is a Method References:
A::B somewhat substitutes the following inline lambda expression: (params ...) -> A.B(params ...)
To correlate this with your questions, it's necessary to understand a java lambda expression. Which is not hard.
An inline lambda expression is similar to a defined functional interface (which is an interface that has no more and no less than 1 method). Let's take a short look what I mean:
InterfaceX must be a functional interface. Any functional interface, the only thing what's important about InterfaceX for that compiler is that you define the format:
InterfaceX can be any of this:
or this
or more generic:
Let's take the first presented case and the inline lambda expression that we defined earlier.
Before Java 8, you could've defined it similarly this way:
Functionally, it's the same thing. The difference is more in how the compiler perceives this.
Now that we took a look at inline lambda expression, let's return to Method References (::). Let's say you have a class like this:
Since method anyFunctions has the same types as InterfaceX callMe, we can equivalate those two with a Method Reference.
We can write it like this:
and that is equivalent to this :
A cool thing and advantage of Method References are that at first, until you assign them to variables, they are typeless. So you can pass them as parameters to any equivalent looking (has same defined types) functional interface. Which is exactly what happens in your case