13.13 Method and Constructor References
So far we have seen that a Java program can use primitive values, objects (including arrays), and lambda expressions. In this section, we introduce the fourth kind of value that a Java program can use, called method references (and their specializations to constructors and array construction). As we shall see, there is a very tight relationship between method references and lambda expressions.
Quite often the body of a lambda expression is just a call to an existing method. The lambda expression simply supplies the arguments required to call and execute the method. In such cases, method references can provide a more concise notation than a lambda expression, potentially increasing the readability of the code. The following code illustrates the relationship between the two notations.
// String -> void
Consumer<String> outLE = obj -> System.out.println(obj); // (1a)
Consumer<String> outMR = System.out::println; // (1b)
outMR.accept(“Save trees!”); // (2)
// Calls System.out.println(“Save trees!”) that prints: Save trees!
The lambda expression at (1a):
obj -> System.out.println(obj)
can be replaced by the method reference at (1b):
System.out::println
The method reference above is composed of the target reference (System.out) on which the method is invoked and the name of the method (println), separated by the double-colon (::) delimiter:
targetReference::methodName
Note that the target reference precedes the double-colon (::) delimiter, and no arguments are specified after the method name. Table 13.11 summarizes the variations in the definition of a method reference which we will discuss in this section.
Table 13.11 Method and Constructor References
Purpose of method reference | Lambda expression/Method reference syntax | Comment |
Designate a static method | (args) -> RefType.staticMethod(args) RefType::staticMethod | |
Designate an instance method of a bounded instance | (args) -> expr.instanceMethod(args) expr::instanceMethod | Target reference provided by the method reference. |
Designate an instance method of an unbounded instance | (arg0,rest)->arg0.instanceMethod(rest) RefType::instanceMethod | arg0 is of RefType. Target reference provided later when the method is invoked. |
Designate a constructor | (args) -> new ClassType(args) ClassType::new | Deferred creation of an instance. |
Designate array construction | arg -> new ElementType[arg][]…[] ElementType[][]…[]::new | Deferred creation of an array. |
A method reference must have a compatible target type that is a functional interface—a method reference implements an instance of a functional interface, analogous to a lambda expression. The compiler does similar type checking as for lambda expressions to determine whether the method reference is compatible with a given target type.
At (1b) above, the function type of the target type Consumer<String> is String -> void. The compiler can infer from the target type that the type of the argument passed to the println() method must be String. The type of the method reference is defined by the type of the method specified in its definition. In this case, the type of the println() method is String -> void, as it accepts a String parameter and does not return a value. Thus the target type Consumer<String> is compatible with the method reference System.out::println. The reference outMR is assigned the value of the method reference at (1b).
Analogous to single-method lambda expressions, method references when executed result in the execution of the method specified in its definition. The instance method println() at (1b) accepts a single String argument. This argument is passed to the method when the functional method accept() of the target type is invoked on the reference outMR, as shown at (2). The method println() is invoked on the same object (denoted by System.out) every time this method reference is executed. Execution of the lambda expression at (1a) will give the same result. Not surprisingly, a method reference and its corresponding single-method lambda expression are semantically equivalent.