This question is pretty closely related to another one. However, I feel like the accepted answer to that question is not quite as definitive.
So, what is the type of a method reference in Java 8? Here's a little demonstration of how a method reference can be "cast" (lifted?) into a java.util.function.Function
:
package java8.lambda;
import java.util.function.Function;
public class Question {
public static final class Greeter {
private final String salutation;
public Greeter(final String salutation) {
this.salutation = salutation;
}
public String makeGreetingFor(final String name) {
return String.format("%s, %s!", salutation, name);
}
}
public static void main(String[] args) {
final Greeter helloGreeter = new Greeter("Hello");
identity(helloGreeter::makeGreetingFor)
.andThen(g -> "<<<" + g + ">>>")
.apply("Joe");
//Compilation error: Object is not a function interface
// Function
// .identity()
// .apply(helloGreeter::makeGreetingFor)
// .andThen(g -> "<<<" + g + ">>>")
// .apply("Joe");
Function
.<Function<String,String>>identity()
.apply(helloGreeter::makeGreetingFor)
.andThen(g -> "<<<" + g + ">>>")
.apply("Joe");
//Compilation error: Cannot resolve method 'andThen(<lambda expression>)'
// (helloGreeter::makeGreetingFor)
// .andThen(g -> "<<<" + g + ">>>")
// .apply("Joe");
// java.lang.invoke.LambdaMetafactory ???
}
private static <I,O> Function<I,O> identity(final Function<I,O> fun1) {
return fun1;
}
}
So, is there a less painful (more straight-forward) way of casting a method reference into a compiled/concrete type which can be passed around?
From the JLS, section 15.13.2, "Type of a Method Reference":
A method reference expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.
...
If a method reference expression is compatible with a target type T, then the type of the expression, U, is the ground target type derived from T.
Basically, the type of the method reference is whatever the context expects it to be. Independent of a context, the method reference doesn't really have a type. There's no way to pass around a "raw" method reference and then turn it into a Function or Consumer or whatever at some later point.
First of all, method references "are compact, easy-to-read lambda expressions for methods that already have a name" (see The Java Tutorials - Method References).
So in fact, you are asking for the type of a lambda expression. This is clearly explained in JLS §15.27.3 (Type of a Lambda Expression).
In short, there are three compatibilities mentioned:
The type of a lambda expression or a method reference is inferred by the compiler. As now several contexts can (and must) be taken into account, Java 8 came with big enhancements for type inference.
The only restriction for lambda expressions is that the inferred type must be a functional interface. In fact, equal lambda expressions can have different types regarding to their context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With