Method Reference and Constructor Reference
Method reference and Constructor reference provide a concise way to refer to existing methods or constructors as lambda expressions.
Method Reference: Refer method of a class
Using the Method Reference the Single Abstract Method of a Functional interface can be mapped to a specific pre-existing method using the ::
(double colon) operator.
Sometimes, all a lambda expression does is call an existing method. In those cases, we can simply refer to the existing method by name.
A method reference is the shorthand syntax for a lambda expression that contains just one method call.
The method being mapped to the Functional interface's Single abstract method can either be static or instance method.
Functional interface's Single abstract method and the mapped method must have the same number and types of argument, the return type can be a subtype of the specified return type (abstract method return type), or a type that can be implicitly converted to the expected return type. The remaining things like modifiers etc. need not match.
Types of Method Reference:
Method Reference can be of three types.
Reference to a static method
Reference to an instance method. (Reference to an instance method of a specific object)
Reference to an instance method of an arbitrary object of a particular type. (Reference to an instance method of an arbitrary object supplied later)
Method Reference | Explanation | Syntax |
Reference to a static method | Reference to a static method of the class | ClassName::methodName |
Reference to an instance method | Reference to an instance method of a specific object | objRef::methodName |
Reference to an instance method of an arbitrary object of a particular type | Reference to an instance method of an arbitrary object supplied later | ClassName::methodName |
A Functional Interface can refer a Lambda Expression or a method.
So, Lambda Expression can be replaced with Method reference. It is an alternative syntax to lambda expression.
Reference to a static method
Lambda expression like:
// If a lambda expression just call a static method of a class
(args) -> Class.staticMethod(args)
can be replaced with the following method reference:
// Shorthand if a lambda expression just call a static method of a class
Class::staticMethod
Example: Lambda expression and Equivalent static method reference
import java.util.function.Predicate;
public class App {
public static void main(String[] args) {
// Lambda expression
Predicate<String> lambda = s -> s.isEmpty();
System.out.println("Lambda Result: " + lambda.test(""));
// Equivalent static method reference
Predicate<String> methodRef = String::isEmpty;
System.out.println("Method Reference Result: " + methodRef.test(""));
}
}
Output:
Lambda Result: true
Method Reference Result: true
Reference to an instance method
Lambda expression like:
// If a lambda expression just call a instance method of an object
(args) -> obj.instanceMethod(args)
can be replaced with the following method reference:
//Shorthand if a lambda expression just call a instance method of an object
obj::instanceMethod
Example: Lambda expression and Equivalent instance method reference
import java.util.function.Predicate;
public class App {
// instance method (can be mapped to SAM of Predicate)
public boolean isEven(int number) {
return number % 2 == 0;
}
public static void main(String[] args) {
// instance of current class
App app = new App();
// Lambda expression
Predicate<Integer> lambda = n -> example.isEven(n);
System.out.println("Lambda Result: " + lambda.test(6)); // Output:
// Equivalent instance method reference
Predicate<Integer> methodRef = app::isEven;
System.out.println("Method Reference Result: " + methodRef.test(6)); // Output:
}
}
Output:
Lambda Result: true
Method Reference Result: true
Reference to an instance method of an arbitrary object of a particular type
Lambda expression like:
// If a lambda expression just call an instance method of a ObjectType
(obj, args) -> obj.instanceMethod(args)
can be replaced with the following method reference:
// Shorthand if a lambda expression just call an instance method of a ObjectType
ObjectType::instanceMethod
public class App {
public static void main(String[] args) {
// Lambda expression
Function<String,String> toUpperCaseLambda = (s)->s.toUpperCase();
// Equivalent lambda expression
Function<String,String> toUpperCaseMethodRefernce = String::toUpperCase;
System.out.println("Lambda Result: "+ toUpperCaseLambda.apply("java8")); // JAVA8
System.out.println("Method Reference Result: "+toUpperCaseMethodRefernce.apply("java8")); // JAVA8
}
}
Output:
Lambda Result: JAVA8
Method Reference Result: JAVA8
Explanation:
In this example, toUpperCase()
is an instance method from String.
The program knows that it can invoke this method on any instance of String, so it can take the reference and any object of that type and be guaranteed the method exists.
This looks very similar to a reference to a static method, but a static reference passes the current object into the method, whereas an arbitrary method reference invokes a method onto the current object.
The difference between the two types of instance method reference is interesting but a bit confusing.
Sometimes, you’ll need to pass something in, other times, the usage of the lambda will supply it for you.In this case you want to call a method that is an instance method of a parameter passed to the function.
With a lambda, there is no problem because you can reference the parameter variable, like this:(String someString) -> someString.toLowerCase();
However, since there is no explicit parameter variable in a method reference, the syntax used instead is:String::toLowerCase;
The compiler takes the "particular type" (String) to reference the functional method (toLowerCase) contained in an "arbitrary object" (the object passed in the parameter).
The term "arbitrary object" is used because the actual object passed in the parameter could be different each time the method reference is executed.
String[] stringArray = { "Barbara", "James", "Mary", "John","Patricia", "Robert", "Michael", "Linda", "George" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
Another Example: for the lambda expression
(String a, String b) -> a.compareToIgnoreCase(b)
It can be replaced with method reference such asString::compareToIgnoreCase
The compiler infers that the instance on which the method will be called is the first parameter of the functional interface's method
Constructor Reference
::
(double colon) operator can also be used for Constructor reference.
Syntax:
ClassName::new
Example:
/*
* Example domonstrating the use of constructor reference
*/
class Sample{
private String s;
Sample(String s){
System.out.println("In Constructor");
this.s = s;
}
public String toString(){
return this.s;
}
}
@FunctionalInterface
interface Interf{
public Sample get(String s);
}
public class App {
public static void main(String[] args) {
//using lambda expression
Interf i1 = s -> new Sample(s);
System.out.println(i1.get("From Lambda Expression"));
System.out.println();
//using constructor reference
// maps the get() method of Interf to one-arg constructor of Sample
Interf i2 = Sample::new;
System.out.println(i2.get("From Constructor ref."));
}
}
Output:
In Constructor
From Lambda Expression<br>
In Constructor
From Constructor ref.