Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a method reference in Java 8 have a concrete type and if so, what is it? [duplicate]

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?

like image 221
Andrey Avatar asked Dec 01 '22 17:12

Andrey


2 Answers

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.

like image 24
user2357112 supports Monica Avatar answered Dec 04 '22 10:12

user2357112 supports Monica


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:

  1. Assignment context
  2. Invocation context
  3. Casting context

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.

like image 83
Seelenvirtuose Avatar answered Dec 04 '22 10:12

Seelenvirtuose