JavaJava 8Technology

Java Method Reference and Constructor Reference

This is Java Method Reference and Constructor Reference Tutorial. Lean how to use a method and constructor reference to pass or assign to an expression with the help of examples.

What is Method Reference ?

Java Method reference is a Lambda Expression that is used to refer a method without invoking it.

The Java Lambda expressions allow us to define an anonymous method and treat it as an instance of functional interface. Similarly, the Method references allow us to do the same thing, but with the existing methods. Also, the Method References are similar to Lambda expressions, that they require a target type. But instead of providing implementation of a method, they refer to a method of an existing class or object.

System::getProperty
"abc"::length
String::length
super::toString
ArrayList::new

The above statements show the general syntax for Method References.

Method Reference Delimiter

In the above example, we see a Java has introduced a new operator :: – called as Method Reference Delimiter.

Where, you place the target reference (or a receiver) before the delimiter and the name of the method (or constructor) after the delimiter. This forms an expression, which is able to refer a method. Also, the method reference expression has an implicit lambda expression which uses the implementation of referred method or constructor at runtime.

Method Reference Example

Now, we will see how to use Method Reference. Before that let’s see an example of using method in Java Stream pipeline without Method Reference.

We will sort a list of Employees based on first name.

employees
    .sort((e1, e2) -> e1.getName().compareTo(e2.getName()));

Here, the lambda expression derives an anonymous implementation of Comparator<Employee> interface. However, if the implementation is multi-line it may look ugly. Also, problem is the implementation is in-line and cannot be reused.

Let’s see how can you refer to a method from another class to reuse it.

public class Utils {
    public int compareEmployees(Employee e1, Employee e2) {
        return e1.getName().compareTo(e2.getName());
    }
}

Now, you have a Utils class with a compareEmployees method. Noteworthy is, this class doesn’t implement Comparator. Let’s see how can we reuse above method to sort the list of Employees.

Utils utils = new Utils();

System.out.println("Before");
employees.forEach(System.out::print);

employees.sort(utils::compareEmployees);

System.out.println("After");
employees.forEach(System.out::print);

Output:

Before
d h g c a b e f 

After
a b c d e f g h 

And, it worked. You have used a method reference using lambda expressions. Takeaway when you refer a method, you don’t need to explicitly assign IS-A relationship.

Static Method Reference

In the last section, you learnt how to refer an instance method of an object in a lambda expression.This time, you will learn how to refer to a static method of a class. A Static Method Reference is similar to the reference of instance method.

public class Utils {
    public static int compareEmployees(Employee e1, Employee e2) {
        return e1.getName().compareTo(e2.getName());
    }
}

The only change is that the compareEmployees is now static. Let’s see how can we use Class in the method reference example we saw earlier.

System.out.println("Before");
employees.forEach(System.out::print);

employees.sort(Utils::compareEmployees);

System.out.println("After");
employees.forEach(System.out::print);

Constructor Reference

Constructor Reference is used to refer to a constructor without instantiating the named class.

The Constructor reference mechanism is yet another game changing addition by Java 8. You can pass references to constructors as arguments or assign to a target type. Similar to method references, you can refer previously defined constructors and assign to a target type of a Functional Interface.

Moreover, in the constructor reference expressions, instead of specifying the exact constructor, we just write new. However, a class may have multiple constructors. In that case, compiler checks the type of the target functional interface with each of the constructors in the class, and finally chooses the best match.

For example, let’s write two different Functional Interface like below. Both have a get method and both return an Employee object. However, the second one accepts a String name.

interface EmployeeEmpty {
    Employee get();
}

interface EmployeeWithName {
    Employee get(String name);
}

After this, lets write Employee class and add two constructors. Out of which one is empty and other takes name and sets it. The Employee doesn’t actually implement either of the interfaces.

class Employee {
    private String name;

    Employee() {
        System.out.println("Empty Constructor");
    }

    Employee(String name) {
        System.out.println("Name Constructor");
        this.name = name;
    }

    public String toString() {
        return "name: " + name;
    }
}

Now, let’s create an empty Employee using Constructor Reference.

EmployeeEmpty empEmpty = Employee::new;

System.out.println("Constructor isn't called yet");
System.out.println(empEmpty.get());

// Output
// Constructor isn't called yet
// Empty Constructor
// name: null

The get method has become a factory method for Employee.
Finally, lets create Employee with name.

 EmployeeWithName empWithName = Employee::new;

System.out.println("Constructor isn't called yet");
System.out.println(empWithName.get("Java"));

// Output
// Constructor isn't called yet
// Name Constructor
// name: Java

You should see the parameterised constructor is called this time. Moreover, in both of the cases the constructors where called lazily.

Summary

In this Java Method Reference and Constructor Reference tutorial you learnt abut how you can reuse a method and constructors using their references and lambda expressions. Additionally, you also learnt how to refer and reuse a static method.

To sum up below are our take aways from this tutorial

  1. Using Method Reference you can reuse a pre-defined method or assign it to the target type.
  2. In the case of polymorphic methods, a correct method is picked up based on the target type interface.
  3. Also, you can replace implementation or a lambda expression of a Functional Interface with any method that matches the signature of the interface’s function. In other words, the class containing the method does not need to implement the interface.
  4. Similarly, in Constructor Reference java uses interface’s function and refers to correct constructor that matches the signature.
  5. Finally, as these are only references to the methods or constructors, the methods or constructors are not invoked lazily.