What are Method Reference in Java 8

Before we start let me tell you that all the code used in this example is located at https://github.com/freetipscentral/java8-methodReferencesExample from where you can download all the examples.

You can also see these example in a step by step manner at our youtube channel.  For your convinience the youtube videos for this tutorial are present below.

Method reference are shorthand notations for Lambda expressions.  Lambda expressions are new addition to Java 8 and they are a way to express anonymous classes in a short notation.  Method references shorten the lambda expressions further in certain scenarios.

Before you should start on method references remember that output of method references can only be applied to functional interface.  This is the same for lambda expressions also.  Lambda expressions can also only be assigned to functional interfaces.

Syntax to use method reference is to have :: between class name and method name.

<Class or Instance>::<method name>

For instance Person::getName is an example of method reference.

When can you use Method Reference

When a lambda expression simply calls a method on a instance or static method on a class, and the parameter of the lambda expressions are directly passed to the method, you can substitute the lambda expression with method reference.

There can be many scenarios where you just take a lambda expression parameter and pass it to a method and the parameter is not mutated in the method.  In those kind of scenarios you can replace the method call in  lambda expression with method reference.  The reason to have method reference is – it makes the code smaller and easier to understand.

For example consider the following lambda expression 

(p) -> System.out.println(p)

We have lambda parameter which is passed to the println instance method of the System.out.  That method simply dumps the parameter in the console.  This is an example of pass through because the lambda expression takes the parameter p and passes it to the prinltln method.  Therefore it can be replaced with the following method reference.

Replace with

System.out::println

The above method reference says that we want to reference the println method.  Java understands from the context that println methods is being invoked with the p object and do the same.  We will see more example below which will make it clearer.

What Are The Types of Method References

There are four types of method references as follows –

  1. Static method reference
  2. Instance method Reference
  3. Instance method of an object of arbitrary type
  4. Constructor method reference

Short Description of various method references.

  1. Static method reference – When method is called on static method of a class.
  2. Instance method Reference – When method is called on instance method of a class.
  3. Instance method of an object of arbitrary type – When you invoke a method on type of the class instance which is one of the lambda target.
  4. Constructor method reference – These are used for constructing and returning objects.

Things to Remember

Since method references are shorthand notation of lambda expressions you should be aware of lambda expression, i.e. what they are and how to write lambda expressions.  You would also need the knowledge of functional interface as all lambda expressions and method references are assigned to instances of functional interfaces.

Practical Examples of Method References and Video Examples

Person.java

package com.freetipscentral.utility;

public class Person {
  String name;
  int age;
  Gender gender;
  int areaCode;
  
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public Gender getGender() {
    return gender;
  }
  public void setGender(Gender gender) {
    this.gender = gender;
  }
  public int getAreaCode() {
    return areaCode;
  }
  public void setAreaCode(int areaCode) {
    this.areaCode = areaCode;
  }
  
  public String toString() {
    return "Name : "+name+" Age : "+age+" Gender : "+gender+" Area Code : "+ areaCode;
  }
  
}

PersonBuilder.java

package com.freetipscentral.utility;

public class PersonBuilder {
  
  Person p1;
  
  public PersonBuilder(Person p1){
    this.p1 = p1;
  }
  
  public static PersonBuilder createPerson() {
    return new PersonBuilder(new Person()); 
  }
  
  public PersonBuilder withName(String name) {
    p1.setName(name);
    return this;
  }
  
  public PersonBuilder withAge(int age) {
    p1.setAge(age);
    return this;
  }
  
  public PersonBuilder withGender(Gender gender) {
    p1.setGender(gender);
    return this;
  }
  
  public PersonBuilder withAreaCode(int areaCode) {
    p1.setAreaCode(areaCode);
    return this;
  }
  
  public Person build() {
    return p1;
  }
}

PersonFactory.java

package com.freetipscentral.utility;

import java.util.ArrayList;
import java.util.List;

public class PersonFactory {
  public static List<Person> createPersons() {
    List<Person> persons = new ArrayList<Person>();
    Person p1 = PersonBuilder.createPerson().withAge(21)
        .withName("Matt")
        .withGender(Gender.MALE)
        .withAreaCode(61244)
        .build();
    persons.add(p1);
    Person p2 = PersonBuilder.createPerson().withAge(33)
        .withName("Alex")
        .withGender(Gender.MALE)
        .withAreaCode(61244)
        .build();
    persons.add(p2);
    Person p3 = PersonBuilder.createPerson().withAge(30)
        .withName("Cindy")
        .withGender(Gender.FEMALE)
        .withAreaCode(61244)
        .build();
    persons.add(p3);

    Person p4 = PersonBuilder.createPerson().withAge(29)
        .withName("Srini")
        .withGender(Gender.MALE)
        .withAreaCode(50131)
        .build();
    persons.add(p4);
    Person p5 = PersonBuilder.createPerson().withAge(41)
        .withName("Paul")
        .withGender(Gender.MALE)
        .withAreaCode(50131)
        .build();
    persons.add(p5);
    Person p6 = PersonBuilder.createPerson().withAge(24)
        .withName("Mindy")
        .withGender(Gender.FEMALE)
        .withAreaCode(50131)
        .build();
    persons.add(p6);

    return persons;
  }
}

Static method reference example 1

StaticMethodRefEx1.java before static method reference

In this example we have a list of Person objects.  We will iterate through the list of person list using the Java 8 internal iterator forEach.  It is invoked with persons.forEach(<Consumer interface implementation>);  The printPerson static method acts as the consumer class implementation since it takes a object and acts on the object.  In this case the method just prints the object on the console.

In case you want to call the printPerson with lambda expression, it can be done in the following manner.

package com.freetipscentral.utility;

import java.util.List;

public class StaticMethodRefEx1 {

  public static void main(String[] args) {
    List<Person> persons = PersonFactory.createPersons();
    persons.forEach(p -> StaticMethodRefEx1.printPerson(p));
    
    //Consumer interface (object) -> public void accept(Object)
    //accept method has Object as input and has accept method which works on the object
    //Does not return anything

  }
  
  public static void printPerson(Person p) {
    System.out.println(p);
  }

}

StaticMethodRefEx1.java after using static method reference

The above lambda implementation invokes the printPerson method on the class, with the person object.  This invocation is just a pass through invocation it can be replaced with method reference.  Here the pass through means the lambda target p which represents the person which is passed to the printPerson method where it is printed.

package com.freetipscentral.utility;

import java.util.List;

public class StaticMethodRefEx1 {

  public static void main(String[] args) {
    List<Person> persons = PersonFactory.createPersons();
    persons.forEach(StaticMethodRefEx1::printPerson);
    
    //Consumer interface (object) -> public void accept(Object)
    //accept method has Object as input and has accept method which works on the object
    //Does not return anything

  }
  
  public static void printPerson(Person p) {
    System.out.println(p);
  }

}

Static method reference example 2.

User.java

package com.freetipscentral.utility;

public class User {
  private int id;
  private String name;
  
  public User(int id, String name) {
    this.id = id;
    this.name = name;
  }
  
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  
  public String toString() {
    return "Id : "+id + " Name :"+name;
  }
}

StaticMethodRefEx2.java implementation with Lambda expressions before static method reference

In this example we use a supplier interface.  The Supplier interface is a functional interface which is used to supply objects.  The supplier interface example used here provides instance of a User object.  The lambda expression equivalent of Supplier interface is () -> <Method name>.

The supplier interface has only one method called get() which gives you back a object.  In  the code below createUser() method is similar to the signature of get() method of supplier interface since it does not have any parameter but returns a object.  Hence this method can represent Supplier interface.  We take advantage of this fact and use this method to point to instance of supplier interface as below.

Once we get hold of the Supplier<User> interface instance we use that variable to get the object and print it.

package com.freetipscentral.utility;

import java.util.function.Supplier;

public class StaticMethodRefEx2 {

  public static void main(String[] args) {
    Supplier<User> userSupplier = () -> StaticMethodRefEx2.createUser();
    System.out.println(userSupplier.get());

    //Supplier Interface represented as () -> Method name
    // Does not take any input
    //Returns the object when get() method is invoked

  }
  
  public static User createUser() {
    User user = new User(1,"Nilendu");
    return user;
  }

}

StaticMethodRefEx2.java  implementation after using Static method reference

The above implementation of lambda expression can be converted and replaced with a static method reference as below.  Here the lamda expression does not take any parameter and just invokes a static method on the StaticMethodRefEx2 class.  The method reference is invoked using StaticMethodRefEx2::createUser as in line 8 below.

package com.freetipscentral.utility;

import java.util.function.Supplier;

public class StaticMethodRefEx2 {

  public static void main(String[] args) {
    Supplier<User> userSupplier = StaticMethodRefEx2::createUser;
    System.out.println(userSupplier.get());

    //Supplier Interface represented as () -> Method name
    // Does not take any input
    //Returns the object when get() method is invoked

  }
  
  public static User createUser() {
    User user = new User(1,"Nilendu");
    return user;
  }

}

Instance Method Reference Example 1

InstanceMethodRefEx1.java implementation with Lambda expressions before instance method reference

Instance method reference is the reference to a method of a instance of a class which is used in a lambda expression.  In this example we are iterating through a list of person class using internal iterator forEach. forEach method takes a instance of Consumer interface as parameter.

The abstract method in the Consumer interface is called accept which takes one object as parameter and returns void.  The printPerson can represent accept method of Consumer interface since, printPerson is a instance method of InstanceMethodRefEx1 object.  printPerson method takes a Person object as input and prints it on the console.  It does not return any value.  The lambda expression to represent Consumer interface is

(object)-> public void accept(object)

Hence we can write a lambda expression for consumer interface using the printPerson like below.  Check the line 12 for the lambda expression.

package com.freetipscentral.utility;

import java.util.List;

public class InstanceMethodRefEx1 {

  public static void main(String[] args) {
    
    InstanceMethodRefEx1 ex1 = new InstanceMethodRefEx1();
    List<Person> persons = PersonFactory.createPersons();
    //persons.forEach(ex1::printPerson);
    persons.forEach((p) -> System.out.println(p)); 
    //Consumer interface (object) -> public void accept(Object)
    //accept method has Object as input and has accept method which works on the object
    //Does not return anything

  }
  
  public void printPerson(Person p) {
    System.out.println(p);
  }

}

InstanceMethodRefEx1.java implementation after instance method reference

The above example is ideal for using method reference.  Logically all we are doing in the lamda expression is just calling the System.out.println method with the object used in the lambda expression.  Here using the method reference is very simple. Just replace the lambda expression with System.out::println which means that the lambda since that is all the lambda expression does.  Check the line 12 for the example here.

package com.freetipscentral.utility;

import java.util.List;

public class InstanceMethodRefEx1 {

  public static void main(String[] args) {
    
    InstanceMethodRefEx1 ex1 = new InstanceMethodRefEx1();
    List<Person> persons = PersonFactory.createPersons();
    //persons.forEach(ex1::printPerson);
    persons.forEach(System.out::println); 
    //Consumer interface (object) -> public void accept(Object)
    //accept method has Object as input and has accept method which works on the object
    //Does not return anything

  }
  
  public void printPerson(Person p) {
    System.out.println(p);
  }

}

Instance Method Reference Example 2

This example is similar to the static method reference example 2 above.  Here we are using method call on object which is instance of the InstanceMethodRefEx2 class.

Before using the instance method reference with a lambda expression the code will look like this –

package com.freetipscentral.utility;

import java.util.function.Supplier;

public class InstanceMethodRefEx2 {

  public static void main(String[] args) {
    
    InstanceMethodRefEx2 ex2 = new InstanceMethodRefEx2();
    Supplier<User> userSupplier = () -> ex2.createUser();
    System.out.println(userSupplier.get());

    //Supplier Interface represented as () -> Method name
    // Does not take any input
    //Returns the object when get() method is invoked

  }
  
  public User createUser() {
    User user = new User(1,"Nilendu");
    return user;
  }

}

The above example can be also converted to method reference with a simple change.  Instead of the lambda expression () -> ex2.createUser(); we can use the method referencee like ex2::createUser as you can see in the following example below.

package com.freetipscentral.utility;

import java.util.function.Supplier;

public class InstanceMethodRefEx2 {

  public static void main(String[] args) {
    
    InstanceMethodRefEx2 ex2 = new InstanceMethodRefEx2();
    Supplier<User> userSupplier = ex2::createUser;
    System.out.println(userSupplier.get());

    //Supplier Interface represented as () -> Method name
    // Does not take any input
    //Returns the object when get() method is invoked

  }
  
  public User createUser() {
    User user = new User(1,"Nilendu");
    return user;
  }

}

Video Tutorial of Method Reference for Instance and Static method references

The above examples are explained in the video below also.  In this video you will find how the lambda expression is derived and then how to converted it to method reference in a step by step manner.

Constructor method reference example 1

ConstructorMethodRefEx1.java before using constructor method reference

In this example we will see how to use constructor method reference to create some objects.  We have a User class which has a constructor which takes two parameters – id and name.  We will create instance of the User class using the constructor User(int id, String name).  The user class looks like below.

User.java

package com.freetipscentral.utility;

public class User {
  private int id;
  private String name;
  
  public User(int id, String name) {
    this.id = id;
    this.name = name;
  }
  
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  
  public String toString() {
    return "Id : "+id + " Name :"+name;
  }
}

We will create a interface which will be used to define methods to create User object.  This interface will be called UserFactory which will contain a abstract method called createUser.  Since this interface contains only one abstract method this is a functional interface.  Hence it can be used as target of lambda expressions.

UserFactory.java

package com.freetipscentral.utility;

public interface UserFactory {
  public abstract User createUser(int id, String name);
}

If you want to create a UserFactory Instance here is how we can do that.

package com.freetipscentral.utility;

public class ConstructorMethodRefEx1 {

  public static void main(String[] args) {
    UserFactory userfactory = new UserFactory() {
            public User createUser(int id, String name) {
                  return new User(id, name);
            }
     }

   //Equivalent lambda expression is 

/*
UserFactory userfactory = (int id, String name) -> new User(id, name);
            
*/
      
    System.out.println(userfactory.createUser(1, "Tony"));
  }

}

 

 

 

package com.freetipscentral.utility;

public class ConstructorMethodRefEx1 {

  public static void main(String[] args) {
    UserFactory userfactory = User::new;
      
    System.out.println(userfactory.createUser(1, "Tony"));
  }

}

 

Source Code Location

https://github.com/freetipscentral/java8-methodReferencesExample