This question already has an answer here:
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":
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 just have a method reference
helloGreeter::makeGreetingFor
, it has no type.If you want to give a type to a method reference without assigning it or passing it as an argument (which assigns it to the parameter), you can cast it:
Method references are just a syntactic sugar for a function that uses passed parameter as an input argument. So, you can assign them this way:
types are inferred and depend on a context.
Your case:
and it is equal to: