Java 8 Method Reference With Examples

After learning concepts of Java 8 Lambda Expressions and Streams, let’s understand one more Java 8 concept, and that is Java 8 method reference. It is one of the key concept which has shorten the Java syntax by new Syntactic Sugar with functional capabilities.

What is Method Reference in Java 8?

Java 8 lambda expression accepts anonymous function as a parameter. In case of providing anonymous method we can also pass references of existing methods or constructors using :: keyword. So method reference can pass existing methods or constructors without invoking them same as lambda expressions.

  • Lambda expressions enable us to define anonymous methods as an instances of functional interfaces
  • Method references enable us to do the same thing but with existing methods and constructors

You can assign a method reference or constructor to any functional interface which has a compatible method with the defined method/constructor.

What are various types of Method References?

In Java 8 there are three types of method reference available,

1) Reference to a static method

Static Method reference refers to the static method of any class.

Syntax: <Class Name>::<Static Method Name>
Example: Integer::valueOf
Lambda: strNum -> Integer.valueOf(strNum)

Here is an example,

public class Java8StaticMethodReference {

    //Static method  
    public static void executeMethod(ActionEvent e){
        System.out.println("Method Reference : Button Label : " 
                                + ((JButton)e.getSource()).getText());
    }
    
    public static void main(String...args) throws Exception{
        
        JButton button1 = new JButton("Java 7");
        JButton button2 = new JButton("Java 8 : Lambda");
        JButton button3 = new JButton("Java 8 : Static Method Reference");
        
        //In earlier releases of Java
        button1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                executeMethod(e);               
            }
        });
        button1.doClick();
        
        //Using Lambda Expressions
        button2.addActionListener(e -> executeMethod(e));
        button2.doClick();
                
        //Using Static Method Reference
        button3.addActionListener(Java8StaticMethodReference::executeMethod);
        button3.doClick();
    }
}
2) Reference to an instance method

Same as Static Method reference, Instance Method reference refers to the instance method of any class.

To understand the Instance Method Reference in detail let us create a base using some basic example of Employee class.

class Employee{
    private String name;
    private int salary;
    
    public Employee(String name, int salary){
        this.name = name;
        this.salary = salary;
    }

    //Instance method which returns the name of an Employee
    public String getName() {
        return name;
    }

    //Instance method which returns the salary of an Employee
    public int getSalary() {
        return salary;
    }
}

And we also have the list of the employees.

List<Employee> empList = Arrays.asList(
    new Employee("Alice M. Albert",104800),
    new Employee("Thomas T. Duarte",111100),
    new Employee("Cory S. Gonsalves",116100),
    new Employee("Susan E. Evans",107200),
    new Employee("Samantha J. Peralta",116600),
    new Employee("Marilyn A. Williams",93100),
    new Employee("Jackeline C. Abeyta",100900),
    new Employee("Juan T. Young",106900),
    new Employee("Barbara J. Brown",114500),
    new Employee("Joseph C. Allred",114600),
    new Employee("Kristin F. Mahar",82000),
    new Employee("Tina J. Woods",114900),
    new Employee("Thomas J. Klein",99100),
    new Employee("Evelyn A. Shafer",101500),
    new Employee("James S. Lunsford",84100),
    new Employee("Christine A. Quinn",109900),
    new Employee("Manuela A. Bowling",98200),
    new Employee("Dean R. Roman",116400),
    new Employee("Yvonne D. Schultz",117700),
    new Employee("Al S. Mains",109300)
);

Basically there are two ways by which you can have a reference to an instance method,

  1. Reference to an Instance Method using class name
  2. Reference to an Instance Method using object instance
Reference to an Instance Method using class name

Syntax: <Class Name>::<Instance Method Name>
Example: Employee::getName
Lambda: e -> e.getName (where e is the Object of type Employee)

Now we have to print name of the employees having salary greater than 100K

So below are the code snippets for different scenarios

//// Traditional Java Way
//Function for getting Employee Name 
Function<Employee, String> getEmployeeNameFunction = new Function<Employee, String>(){
    @Override
    public String apply(Employee e) {
        return e.getName();
    }
};
        
empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(getEmployeeNameFunction)
            // Use that function to map Employee to String (Employee Name)
    .forEach(e -> System.out.println(e));  

//// Using Lambda in Java 8
empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(e -> e.getName())
            // Lambda Expression to map Employee to String (Employee Name)
    .forEach(e -> System.out.println(e));
    
//// Using Instance Method Reference in Java 8
empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(Employee::getName)
            // Instance Method Reference to map Employee to String (Employee Name)
    .forEach(e -> System.out.println(e));

In above example if you have observed, e -> e.getName() is replaced by to Employee::getName which is reference to an instance method using class name.

Points to be considered for using reference to an instance method using class name are,

  • Class Name should be of the reference type returned from previous pipeline function
    • For Example, in our case we have used Class Name Employee because previous method of map() is filter() and it returns the stream of Employee class
  • Instance Method should be of the class with reference type returned from previous pipeline function
    • For Example, considering above point, getName() is the method of Employee class so we have used Employee::getName which internally call getName() for each elements and will return a stream of String which contains the names of all filtered employees

Before we go into the more details let’s define a new EmpUtil class which has one instance method accepting Employee object as a parameter and returning First name of the employee.

//Employee Utility class
class EmpUtil{
    public String getFirstName(Employee e){
        return e.getName().split(" ")[0];
    }
}
Reference to an Instance Method using object instance

Syntax: <Object Name>::<Instance Method Name>
Example: empUtil::getFirstName
Lambda: e -> empUtil.getFirstName(e) (where e is the Object of type Employee and empUtil is the object of EmpUtil class)

To understand Reference to an Instance Methods using object instance, let us take one example to print only first name of the employees having salary greater than 100K

Below are the code snippets for that,

EmpUtil empUtil = new EmpUtil();

//// Traditional Java Way
//Function for getting Employee First Name 
Function<Employee, String> getEmployeeFirstNameFunction = new Function<Employee, String>(){
    @Override
    public String apply(Employee e) {
        return empUtil.getFirstName(e);
    }
};
        
empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(getEmployeeFirstNameFunction) 
            // Use that function to map Employee to String (Employee First Name)
    .forEach(e -> System.out.println(e));

//// Using Lambda in Java 8
empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(e -> empUtil.getFirstName(e)) 
            // Lambda Expression to map Employee to String (Employee First Name)
    .forEach(e -> System.out.println(e));

//// Using Instance Method Reference in Java 8
empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(empUtil::getFirstName) 
            // Instance Method Reference to map Employee to String (Employee First Name)
    .forEach(e -> System.out.println(e));

You can observe that in above example we have used reference to an instance method using object instance empUtil.

Major difference here is we are using some third party utility class which is completely irrelevant than return type objects which are there in stream pipeline method filter() and still we are using that as a method reference.

We can use reference of this instead of empUtil if getFirstName() utility method is defined in the same class where our example code is written. We can also use reference of super instead of empUtil if getFirstName() utility method is defined in the base class of the class where our example code is written.

3) Reference to a constructor

Same as Method references, we can also refer to constructor of any class. Such references are known as Constructor Reference.

Syntax: <Class Name>::new
Example: String[]::new
Lambda: size -> new String[size]

Let’s say in above example if we want to store First name of all employees in String[] whose salary is greater than 100K, again we can write code in three different ways,

//// Traditional Java Way
//Function for returning newly initialized array of String   
IntFunction<String[]> getArraySize = new IntFunction<String[]>() {
    public String[] apply(int value) {
        return new String[value];
    }
};
                
String[] array = empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(empUtil::getFirstName)
    .toArray(getArraySize);
        
//// Using Lambda in Java 8
String[] array = empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(empUtil::getFirstName)
    .toArray(size -> new String[size]);

//// Using Instance Method Reference in Java 8
String[] array = empList.stream()
    .filter(e -> e.getSalary() > 100000)
    .map(empUtil::getFirstName)
    .toArray(String[]::new);

Hope this information is helpful to all Readers of backtobazics.com. Stay tuned for such interesting articles and let me know you thoughts by your valuable comments.

 

One thought on “Java 8 Method Reference With Examples”

Leave a Reply to zmeeagain Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>