Method reference and Constructor reference provides a concise way to refer to existing methods or constructors as lambda expressions.
Using the Method Reference the Single Abstract Method of Functional Interface can be mapped to a specific pre-existing method using :: (double colon) operator.
Sometimes, a lambda expression only calls an existing method. In those cases, we can simply refer 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 Functional Interface SAM can be either static or instance method.
Functional Interface SAM and the mapped method must have same number and types of argument, the return type can be a subtype of the specified return type (SAM return type), or a type that can be implicitly converted to the expected return type. The remaining things like modifiers etc. need not to match.
Example: Method reference with different but compatible return type
- 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 a arbitrary object supplied later)
Method Reference | Explanation | Syntax |
---|---|---|
Reference to a static method | Reference to static method of a 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 a arbitrary object supplied later | ClassName::methodName |
- Functional Interface can refer Lambda Expressions and Functional Interface can also refer method reference.
- So, Lambda Expression can be replaced with method reference. Method reference is alternative syntax to lambda expression.
Lambda expression like:
// If a lambda expression just call a static method of a class
(args) -> Class.staticMethod(args)
Can be replaced with 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;
/*
* Example demonstrating use of static method reference
*/
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
Lambda expression is like:
// If a lambda expression just call a default method of an object
(args) -> obj.instanceMethod(args)
Can be replaced with following method reference:
//Shorthand if a lambda expression just call a default method of an object
obj::instanceMethod
Example: Lambda expression and Equivalent instance method reference
import java.util.function.Predicate;
/*
* Example demonstrating use of static method reference
*/
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
Lambda expression like:
// If a lambda expression just call an instance method of a ObjectType
(obj, args) -> obj.instanceMethod(args)
Can be replaced with 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 as
String::compareToIgnoreCase
The compiler infers that the instance on which the method will be called is the first parameter of the functional interface's method
Example: Method Reference
Example 2: Method Reference
Example 3: Method Reference
:: (double colon) operator can also be used for Constructor reference.
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.
Example: Constructor Reference
Example: Constructor Reference