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.

  1. Reference to a static method

  2. Reference to an instance method. (Reference to an instance method of a specific object)

  3. 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 ReferenceExplanationSyntax
Reference to a static methodReference to a static method of the classClassName::methodName
Reference to an instance methodReference to an instance method of a specific objectobjRef::methodName
Reference to an instance method of an arbitrary object of a particular typeReference to an instance method of an arbitrary object supplied laterClassName::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 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

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.