Java 8 Features — Method References

Method References

Prepared by Srikanth Mamillapalli

1. Java Method References

Method References allow us to define Lambda Expressions by explicitly referring to methods by their names.

Java provides a new feature called Method Reference in Java 8. A method reference is used to refer to a method of a functional interface.

It is a compact and easy form of a Lambda Expression. Whenever a Lambda Expression is used only for referring to an existing method, the Lambda Expression can be replaced with a Method Reference.

Key idea: Method Reference is essentially a shorter form of a Lambda Expression when the lambda only calls an existing method.

Basic Examples

Method ReferenceEquivalent Lambda Expression
String::toStrings -> s.toString()
String::toLowerCases -> s.toLowerCase()
String::lengths -> s.length()
Integer::compareTo(i1, i2) -> i1.compareTo(i2)
String::compareTo(s1, s2) -> s1.compareTo(s2)

2. Types of Method References

The source describes three main types of Method References:

1. Static Method Reference

Reference to a static method of a class.

ClassName::staticMethodName

2. Instance Method Reference

Reference to an instance/non-static method.

ObjectName::instanceMethodName

3. Constructor Reference

Reference to a class constructor.

ClassName::new

CaseLambda ExpressionMethod Reference Equivalent
Static Method (args) -> ClassName.staticMethodName(args) ClassName::staticMethodName
Instance Method (args) -> ObjectName.instanceMethodName(args) ObjectName::instanceMethodName
Constructor (args) -> new ClassName(args) ClassName::new

3. Lambda Expression vs Method Reference

Lambda Expression
Calls Existing Method
Method Reference

Example

// Lambda Expression
s -> s.toString()

// Method Reference
String::toString
The method reference is useful when the Lambda Expression does nothing except invoke an already existing method.

4. Method Reference to a Static Method of a Class

The PDF uses a functional interface named A and a class named Digit.

interface A {
    public boolean checkSingleDigit(int x);
}

class Digit {

    public static boolean isSingleDigit(int x) {
        return x > -10 && x < 10;
    }
}

Using Lambda Expression

public class TestStaticMethodReference {

    public static void main(String[] args) {

        A a1 = (x) -> {
            return x > -10 && x < 10;
        };

        System.out.println(
            a1.checkSingleDigit(10)
        );
    }
}

Using Method Reference

public class TestStaticMethodReference {

    public static void main(String[] args) {

        A a2 = Digit::isSingleDigit;

        System.out.println(
            a2.checkSingleDigit(9)
        );
    }
}
Pattern: ClassName::staticMethodName

5. Method Reference to an Instance Method of a Class

interface B {
    public void add(int x, int y);
}

class Addition {

    public void sum(int a, int b) {
        System.out.println(
            "The sum is :" + (a + b)
        );
    }
}

Using Lambda Expression

public class TestInstanceMethodReference {

    public static void main(String[] args) {

        Addition addition = new Addition();

        B b1 = (a, b) ->
            System.out.println(
                "The sum is :" + (a + b)
            );

        b1.add(10, 14);
    }
}

Using Method Reference

public class TestInstanceMethodReference {

    public static void main(String[] args) {

        Addition addition = new Addition();

        B b2 = addition::sum;

        b2.add(100, 140);
    }
}
Pattern: ObjectName::instanceMethodName

6. Constructor Reference

A Constructor Reference provides a compact way to refer to a constructor using ClassName::new.

interface C {
    public Employee getEmployee();
}

interface D {
    public Employee getEmployee(
        String name,
        int age
    );
}

class Employee {

    String eName;
    int eAge;

    public Employee() {}

    public Employee(
            String eName,
            int eAge) {

        this.eName = eName;
        this.eAge = eAge;
    }

    public void getInfo() {
        System.out.println(
            "I am a method of class Employee"
        );
    }
}

Using Lambda Expression

C c1 = () -> new Employee();
c1.getEmployee().getInfo();

D d1 = (name, age) ->
    new Employee(name, age);

d1.getEmployee("Tony", 34).getInfo();

Using Constructor Reference

C c2 = Employee::new;
c2.getEmployee().getInfo();

D d2 = Employee::new;
d2.getEmployee("Tony", 34).getInfo();
Pattern: ClassName::new

7. Static Method Reference with List.forEach()

The source demonstrates passing a static method reference to List.forEach().

public class MainStaticReference {

    public static void main(String[] args) {

        List<String> list =
            Arrays.asList("Hello", "World");

        list.forEach(
            Utils::printMessage
        ); // static method reference
    }
}

Utility Class

package com.fortress.java.preparation;

public class Utils {

    public static void printMessage(
            String message) {

        System.out.println(message);
    }
}
List
forEach()
Utils::printMessage

8. Instance Method Reference of a Particular Object

The source demonstrates a method reference to a specific object instance.

public class MainInstanceMethodReference {

    public static void main(String[] args) {

        Printer printer = new Printer();

        List<String> list =
            Arrays.asList("Java", "8");

        list.forEach(
            printer::print
        ); // instance method reference
    }
}
Concept: The reference printer::print points to the print() method belonging to the particular printer object.

9. Instance Method Reference of an Arbitrary Object of a Particular Type

The PDF also demonstrates a method reference where the method is called on each object supplied by the stream/collection operation.

public class MainArbitraryObject {

    public static void main(String[] args) {

        List<String> names =
            Arrays.asList(
                "srikanth",
                "vihas",
                "kalyani"
            );

        names.sort(
            String::compareToIgnoreCase
        ); // instance method reference
    }
}

Another Example from the Source

List<String> names =
    Arrays.asList(
        "Alice",
        "bob",
        "Charlie"
    );

names.sort(
    String::compareToIgnoreCase
); // sort ignoring case

names.forEach(
    System.out::println
); // print using System.out.println
Important distinction: In this form, the referenced instance method is associated with the object supplied by the operation rather than one separately created target object.

10. Constructor Reference with Supplier

The source demonstrates using a constructor reference with the Supplier functional interface.

import java.util.function.Supplier;

public class MainMethodReferenceConstructor {

    public static void main(String[] args) {

        Supplier<MyClass> supplier =
            MyClass::new; // constructor reference

        MyClass obj =
            supplier.get(); // invokes constructor
    }
}
Supplier<MyClass>
MyClass::new
supplier.get()
New Object

11. Complete Method Reference Demonstration

Static Method

static class Utils {

    public static void printStatic(
            String message) {

        System.out.println(
            "[Static] " + message
        );
    }
}

Instance Method of a Particular Object

static class Printer {

    public void printInstance(
            String message) {

        System.out.println(
            "[Instance] " + message
        );
    }
}

Constructor

static class MyClass {

    public MyClass() {

        System.out.println(
            "[Constructor] MyClass object created!"
        );
    }
}

Using All Four Forms

public static void main(String[] args) {

    List<String> messages =
        Arrays.asList(
            "Java",
            "Method",
            "Reference"
        );

    // 1. Static Method Reference
    messages.forEach(
        Utils::printStatic
    );

    // 2. Instance Method of a Particular Object
    Printer printer = new Printer();

    messages.forEach(
        printer::printInstance
    );

    // 3. Instance Method of an Arbitrary Object
    //    of a Particular Type
    List<String> names =
        Arrays.asList(
            "Alice",
            "bob",
            "Charlie"
        );

    names.sort(
        String::compareToIgnoreCase
    ); // sort ignoring case

    names.forEach(
        System.out::println
    );

    // 4. Constructor Reference
    Supplier<MyClass> supplier =
        MyClass::new;

    MyClass obj =
        supplier.get(); // invokes constructor
}

12. Quick Revision

Type Syntax Equivalent Lambda
Static Method ClassName::staticMethodName (args) -> ClassName.staticMethodName(args)
Instance Method — Particular Object ObjectName::instanceMethodName (args) -> ObjectName.instanceMethodName(args)
Instance Method — Arbitrary Object ClassName::instanceMethodName Method invoked on the object supplied by the functional operation.
Constructor ClassName::new (args) -> new ClassName(args)

Easy Memory Trick

Static

ClassName::method

No object is required.

Particular Object

object::method

Uses a specific object.

Arbitrary Object

ClassName::method

Method operates on objects supplied by the functional operation.

Constructor

ClassName::new

Creates a new object.

One-line summary: If a Lambda Expression simply invokes an existing method or constructor, Method Reference can make the code shorter and more readable.