Method References

Author: Tatyana Milkina

1. What is a Method Reference

Lambda expressions are used to create anonymous methods. In cases when a lambda expression invokes only one existing method, it is better to refer to the existing method by name. Method references give the possibility to do this. They are compact lambda expressions for methods that already have a name.

For example, the next lambda expression calls only one method:

Consumer<String> consumer = str -> System.out.println(str);

It can be rewritten with method reference, which makes the code clearer:

Consumer<String> consumer = System.out::println;

There are four types of method references:

Types of method references
Type Example
Reference to a static method ContainingClass::staticMethodName
Reference to an instance method of a particular object containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type ContainingType::methodName
Reference to a constructor ClassName::new

2. Reference to a Static Method

Syntax:

ContainingClass::staticMethodName

Let's refactor an example, where we are using a static method of a Boolean class:

Function<String, Boolean> function = e -> Boolean.valueOf(e);
System.out.println(function.apply("TRUE"));

 With a method reference, the code looks like:

Function<String, Boolean> function = Boolean::valueOf;
System.out.println(function.apply("TRUE"));

3. Reference to an Instance Method of a Particular Object

Syntax:

containingObject::instanceMethodName

This type of method references is used when a lambda expression calls a method of an external object that already exists.

For example, let's refactor the example:

Consumer<String> consumer = e -> System.out.println(e);
consumer.accept("OCPJP 8");

Since System.out is an instance of type PrintStream, we can rewrite the previous example as:

Consumer<String> consumer = System.out::println;
consumer.accept("OCPJP 8");

 Or let's look at another example:

Integer integer = new Integer(5);
Supplier<String> supplier = () -> integer.toString();
System.out.println(supplier.get());

After refactoring, the code will be:

Integer integer = new Integer(5);
Supplier<String> supplier = integer::toString;
System.out.println(supplier.get());

4. Reference to an Instance Method of an Arbitrary Object of a Particular Type

Syntax:

ContainingType::methodName

It is called a non-static method, but a class name is used for this type of method reference. Actually, the instance of the class is passed when the method is called.

Let's look at the lambda expression, where the non-static String.toLowerCase method is utilized:

Function<String, String> function = s -> s.toLowerCase();
System.out.println(function.apply("OCPJP 8"));

It can be refactored as: 

Function<String, String> function = String::toLowerCase;
System.out.println(function.apply("OCPJP 8"));

5. Reference to a Constructor

Syntax:

ClassName::new

The ClassName shouldn't be the name of an abstract class or interface.

Let's refactor the example:

Function<String, Integer> function = (d) -> new Integer(d);
System.out.println(function.apply("4"));

The result is:

Function<String, Integer> function = Integer::new;
System.out.println(function.apply("4"));

The exact constructor isn't specified in a constructor reference expression. When a class declares multiple constructors, the compiler will check the type of the functional interface with all the constructors and choose the best match:

Function<String, Integer> function1 = (d) -> new Integer(d);
Function<Integer, Integer> function2 = (d) -> new Integer(d);
System.out.println(function1.apply("4"));
System.out.println(function2.apply(4));
Читайте также:
Комментарии