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
?
In java-8 Streams Reducer in simple works is a function which takes two values as input and returns result after some calculation. this result is fed in next iteration.
in case of Math:max function, method keeps returning max of two values passed and in the end you have largest number in hand.
return reduce(Math::max);
is NOT EQUAL toreturn reduce(max());
But it means, something like this:
You can just save 47 keystrokes if you write like this
I found this source very interesting.
In fact, it is the Lambda that turns into a Double Colon. The Double Colon is more readable. We follow those steps:
STEP1:
STEP2:
STEP3:
Since many answers here explained well
::
behaviour, additionally I would like to clarify that::
operator doesnt need to have exactly same signature as the referring Functional Interface if it is used for instance variables. Lets assume we need a BinaryOperator which has type of TestObject. In traditional way its implemented like this:As you see in anonymous implementation it requires two TestObject argument and returns a TestObject object as well. To satisfy this condition by using
::
operator we can start with a static method:and then call:
Ok it compiled fine. What about if we need an instance method? Lets update TestObject with instance method:
Now we can access instance as below:
This code compiles fine, but below one not:
My eclipse tell me "Cannot make a static reference to the non-static method testInstance(TestObject, TestObject) from the type TestObject ..."
Fair enough its an instance method, but if we overload
testInstance
as below:And call:
The code will just compile fine. Because it will call
testInstance
with single parameter instead of double one. Ok so what happened our two parameter? Lets printout and see:Which will output:
Ok so JVM is smart enough to call param1.testInstance(param2). Can we use
testInstance
from another resource but not TestObject, i.e.:And call:
It will just not compile and compiler will tell: "The type TestUtil does not define testInstance(TestObject, TestObject)". So compiler will look for a static reference if it is not the same type. Ok what about polymorphism? If we remove final modifiers and add our SubTestObject class:
And call:
It will not compile as well, compiler will still look for static reference. But below code will compile fine since it is passing is-a test:
::
is a new operator included in Java 8 that is used to refer a method of an existing class. You can refer static methods and non-static methods of a class.For referring static methods, the syntax is:
For referring non-static methods, the syntax is
And
The only prerequisite for referring a method is that method exists in a functional interface, which must be compatible with the method reference.
Method references, when evaluated, create an instance of the functional interface.
Found on: http://www.speakingcs.com/2014/08/method-references-in-java-8.html
The previous answers are quite complete regarding what
::
method reference does. To sum up, it provides a way to refer to a method(or constructor) without executing it, and when evaluated, it creates an instance of the functional interface that provides the target type context.Below are two examples to find an object with the max value in an
ArrayList
WITH and WITHOUT the use of::
method reference. Explanations are in the comments below.WITHOUT the use of
::
WITH the use of
::