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

What Are Default Methods in Java 8

Default methods were added in Java 8 to allow adding of new methods to interface without breaking existing implementing classes.  Using default methods we can add functionality to existing classes which implemented a common interface.

Note – All the Java source files in this project can be found at https://github.com/freetipscentral/java8-defaultmethod

Here is one example of Default method

Lets assume that we have a GenericRemote interface and two classes which implement the interface.

package com.freetipscentral.defaultmethod;

public interface GenericRemote {
  
  public void startDevice();
}

 

package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
}
package com.freetipscentral.defaultmethod;

public class MusicSystemRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("Music System Started");
  }
}

In the above example you can see that two classes TVRemote and MusicSystemRemote implementing the interface GenericRemote hence they also implement the method startDevice().

Now consider the situation where in you need to add one more method stopDevice() to the interface GenericRemote interface.

Before Java 8 as soon as you add that method to the GenericRemote interface all the classes below will start having compilation problems.  You can solve the compilation problems by implementing the method in all the classes which implement this interface.  Same happens in Java 8 also.

But Java 8 has a more elegant solution for this.  That is called Default method.  Default method are a way to add a default implementation of the interface method on the interface itself.  That way if the interface undergoes changes after it has been implemented by many classes, those classes will not have compilation errors.

How to Add a Default Implementation Method

To add a default implementation add the keyword default at the start of the method signature and then implement the method.  Here is how the above implementations will look like after adding the default method.  Notice how the implementing classes have not undergone any changes.

package com.freetipscentral.defaultmethod;

public interface GenericRemote {
 
 public void startDevice();
 
 default public void stopDevice() {
 System.out.println("Default Stop Device");
 }
}
package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
}
package com.freetipscentral.defaultmethod;

public class MusicSystemRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("Music System Started");
  }
}

Do The Implementing Classes Have Choice to Overriding Default Methods

Yes implementing classes can always override the default method and add their own implementation.  That way they can have the best of both worlds.

For example TVRemote class can always override the default implementation as below.

package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
  
  @Override
  public void stopDevice() {
    System.out.println("TV Stopped");
  }
}

 

Why Default methods were added to Java 8

Default methods were added to Java so that backwards compatibility could be maintained with older collection framework.  One of the new method added to the Collection interface is forEach.  forEach is an internal iterator which has been  added to Iterable interface in Java 8.  Collection interface extends Iterable interface.  This method helps in iterating through the objects in the collection.  For example consider the following example –

Here is what is being done in the code.

  1. Create a list of Students.
  2. Add Student objects to the list
  3. Iterate through the list and print the students.

If you notice carefully we are using forEach which is an internal iterator.  Since this is new addition to the Collection framework  all the previously written codes (running in millions of lines) which used Collection interface such as List or Set would have failed.  Hence Java 8 added the default method so that the code remains backward compatible.  If you see the Oracle documentation on Iterable interface you will see that forEach is a default method.  Here is the link to Oracle documentation on Iterable interface.

package com.freetipscentral.defaultmethod;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import com.freetipscentral.defaultmethod.domain.Student;

public class StudentManager {
  public static void main(String args[]) {
    List<Student> students = new ArrayList<Student>();
    
    //Create Students and add to list
    Student student1 = new Student("Karen",1);
    Student student2 = new Student("Rahul",2);
    students.add(student1);
    students.add(student2);
    
    //Iterate through the list and print the student objects
    students.forEach(new Consumer<Student>() {
      public void accept(Student s) {
        System.out.println(s);
      }
    });
  }
}

What happens when a class inherits two interfaces with default methods with same name

If a class implements two interfaces with same default method name then it will cause compile error in the class.  The solution is to implement the default method in the class.

What Happens When an Interface Extends Another Interface With Default Method

If an interface extends another interface which has default method then the interface and its implementing classes also have access to the default method.

However the child interface can also make it abstract.  It the child interface makes it abstract then the implementing classes of the child interface have to implement the method.  Here is an example of how child interface can make the default method abstract.  All classes implementing MobileRemote need to implement stopDevice() method.

package com.freetipscentral.defaultmethod;

public interface MobileRemote extends GenericRemote {
  public void stopDevice();
}

The child interface can also override the default interface with its own default method.  In this case the implementing classes of the child interface can use the default method of the child interface.   Here is an example of how child interface can override the default method.

package com.freetipscentral.defaultmethod;

public interface CarRemote extends GenericRemote {
  default public void stopDevice() {
    System.out.println("Stop the Car");
  }
}

 

 

Lambda Expression Tutorial

Lambda expressions are one of the new additions to Java 8.  It is also one of the most talked about and exiting features of Java 8.  We will cover what exactly are Lambda expressions and some examples in this article.

What are Lambda Expressions?

Lambda expressions are a way use a expression to represent function calls which are usually on anonymous classes.  Usually anonymous inner classes have just one method and extend some interface.  The entire purpose of writing anonymous inner classes is to implement a single method.  Lambda expressions can help us reduce the code written around anonymous inner classes by reducing to to a single statement.

Here is a simple example of Lambda expression –

( i ) -> (System.out.println(i));

Let us see an example.

In the following class following is happening –

Let us assume that you want to sort a array list of Integers using a anonymous class which implements Comparator interface.  Here are the steps –

  1. Initialize a ArrayList of integers. (Line 10)
  2. We want to sort the numbers in the list so we take help of anonymous class which implements Comparator interface (Line 11).  There is only one method inside it called compare which contains the logic for comparison.  We call the compare method in the instance of the anonymous class (Line 12).  This method compares the values in the list and returns a sorted list.
  3. Once the list is sorted we print the list (Line 17 – 20).
package com.freetipscentral.domain;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class LambdaExample1 {
  public static void main(String args[]) {
    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,20);
    Collections.sort(numbers, new Comparator<Integer>(){
      public int compare(Integer i1, Integer i2){
        return i1.compareTo(i2);
      }
    });
    
    for(Integer i : numbers) {
      System.out.println(i);
    }
  }
}

Here is the output of above code –

1
2
3
4
5
6
7
8
9
20

Lambda Expression For the Above Code

The above code can also be written using Lambda expressions.  Once we translate the Anonymous class to Lambda expression here is how the class looks like –

package com.freetipscentral.domain;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class LambdaExample1 {
  public static void main(String args[]) {
    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,20);
    Collections.sort(numbers, (Integer i1, Integer i2) -> i1.compareTo(i2));
    
    for(Integer i : numbers) {
      System.out.println(i);
    }
  }
}

In the code above the actual Lambda expression is only the following code.

(Integer i1, Integer i2) -> i1.compareTo(i2)

If you run the above class the output would be same as above.  However there are two things which have happened in the code. Firstly the number of lines of code has decreased and secondly code is also simpler to understand.  If you do not find it east then do not worry.  I will explain how to do it.

Steps to reduce anonymous class function call to Lambda expressions

There are only three conceptual things you need to take care while converting a function call to Lambda expression.

  1. You only need the parameter list on the left and method body on the right.
  2. Parameter and the method body will be separated by ->
  3. Remove everything else including name of the method and return type.  They are all inferred.  The return statement is also not needed as that is inferred.

Let us see the above steps in the following example where we will convert the function call to Lambda expression.

Collections.sort(numbers, new Comparator<Integer>(){
  public int compare(Integer i1, Integer i2){
    return i1.compareTo(i2);
  }
});

The anonymous class starts at new Comparator ...

Remove from new till end of compare.  You will have the following code.

Collections.sort(numbers, (Integer i1, Integer i2){
    return i1.compareTo(i2);
  }
});

Replace { with -> at the end of the first line. Also remove the return keyword at the beginning of second line as that is implicit.

Collections.sort(numbers, (Integer i1, Integer i2) ->
    i1.compareTo(i2);
  }
});

Last step is to remove the braces for the function ending and the anonymous class at the end.  After you remove here is the code.

Replace { with -> at the end of the first line.

Collections.sort(numbers, (Integer i1, Integer i2) ->
  i1.compareTo(i2);
);

Here is the code after formatting.

Collections.sort(numbers, (Integer i1, Integer i2) -> i1.compareTo(i2);
);