In Java 8 there is \"Method Reference\" feature. One of its kind is \"Reference to an instance method of an arbitrary object of a particular type\"
http://docs.oracl
It is a reference to an instance method from some type. In the case of the example, compareToIgnoreCase
is a method from String
. The program knows that it can invoke this method on an instance of String
, so it can take the reference and any object of that type and be guaranteed the method exists.
I would compare this to the Method
class in that they refer to a method and can be invoked on an arbitrary instance of some type.
For the example, it can use two String
objects and call compareToIgnoreCase
on one and use the other as an argument to match the method signature. This allows it to take the array and sort it based on any method of the array type instead of requiring a comparator instance to do this instead.
And here is the example for anyone who didn't click on the link in the question:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda", "George" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
The example given from the Oracle Doc linked is:
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
The lambda equivalent of
String::compareToIgnoreCase
would be
(String a, String b) -> a.compareToIgnoreCase(b)
The Arrays.sort()
method is looking for a comparator as its second argument (in this example). Passing String::compareToIgnoreCase
creates a comparator with a.compareToIgnoreCase(b)
as the compare method's body. You then ask well what's a
and b
. The first argument for the compare method becomes a
and the second b
. Those are the arbitrary objects, of the type String (the particular type).
Don't understand?
Read more at the source: http://moandjiezana.com/blog/2014/understanding-method-references/
Please see the below code sample which explains "Reference to an Instance Method of an Arbitrary Object of a Particular Type" category described in https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
import java.util.Arrays;
class Person{
String name;
//constructor
public Person(String name){
this.name = name;
}
//instance method 1
public int personInstanceMethod1(Person person){
return this.name.compareTo(person.name);
}
//instance method 2
public int personInstanceMethod2(Person person1, Person person2){
return person1.name.compareTo(person2.name);
}
}
class Test {
public static void main (String[] args) throws Exception{
Person[] personArray = {new Person("A"), new Person("B")};
// Scenario 1 : Getting compiled successfully
Arrays.sort(personArray, Person::personInstanceMethod1);
// Scenario 2 : Compile failure
Arrays.sort(personArray, Person::personInstanceMethod2);
// Scenario 3 : Getting compiled successfully.
Person personInstance = new Person("C");
Arrays.sort(personArray, personInstance::personInstanceMethod2);
// Scenario 4 : Getting compiled successfully. As the same way as "Scenario 1"
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
}
}
Scenario 1 and Scenario 4 describes "Reference to an Instance Method of an Arbitrary Object of a Particular Type" category described in https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
If the method parameter takes a variable in same instance Type as the instance Type of the element, you can call that instance method using Type.(Person::personInstanceMethod1)
Compare "personInstanceMethod1" instance method in "Person" class with "compareToIgnoreCase" instance method in "String" class (https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareToIgnoreCase-java.lang.String-) to see the similarity. Both are taking a single parameter with the same Type.
Compare Scenario 1 and Scenario 2 to see the difference.
Let me put it another way. So, if your lambda expression looks like the following:
(<ContainingType arg>, <otherArgs>) -> arg.instanceMethod(<otherArgs>)
It can be replaced with method reference such as
ContainingType::instanceMethod
So, for the lambda expression
(String a, String b) -> a.compareToIgnoreCase(b)
It can be replaced with method reference such as
String::compareToIgnoreCase
Here, the particular type is the ContainingType which is String. And an instance of it (String) is arbitrary since we haven't declared or initialized it yet and these are simply the arguments here. And hence "arbitrary object of particular type" in this context is "arbitrary object of String type"
In this case there is an array of objects of a particular type(String) and any random object in array can call its instance method . This approach allows a class to refer to its instance method as if it is a static method .
Also this approach works only for built in class of java like String but not for user defined class . In case of user defined class the instance method can only be referred by its object .