3

Этот вопрос очень тесно связан с another one. Однако я чувствую, что принятый ответ на этот вопрос не совсем окончательный.Имеет ли ссылка на метод в Java 8 конкретный тип, и если да, то что это такое?

Итак, что является Тип ссылки метода в Java 8? Вот небольшая демонстрация того, как эталонный метод может быть «слепок» в 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; 
    } 
} 

Итак, есть менее болезненный (более прямолинейный) способ литья ссылки на метод в скомпилированный/бетонный тип, который можно передавать?

+3

'Функция f = helloGreeter :: makeGreetingFor; '? Вывод типа ссылки метода. Эта же ссылка на метод может использоваться как пользователь, функция или другие функциональные интерфейсы в зависимости от контекста. –

+3

Если вы чувствуете, что на вопрос не ответил достаточно хорошо, вы должны предложить щедрость по оригинальному вопросу, а не спрашивать его во второй раз. Есть ли способ, которым ваш вопрос отличается от предыдущего, или я могу закрыть его как дубликат? –

+0

Я полагаю, в сущности, они одинаковы. хотя ответы здесь кажутся более конкретными. Я закрою его сам. – Andrey

ответ

5

Ссылки на методы - это всего лишь синтаксический сахар для функции, которая использует переданный параметр в качестве входного аргумента. Таким образом, вы можете назначить их таким образом:

Runnable runnable = System.out::println; 
Consumer consumer = System.out::println; 

типы выводятся и зависят от контекста.

Ваш случай:

Function<String, String> foo = helloGreeter::makeGreetingFor; 

и она равна:

Function<String, String> foo = s -> helloGreeter.makeGreetingFor(s); 
5

Прежде всего, ссылки на метод «компактные, легко читаемый лямбда-выражения для методов, которые уже есть имя "(см. The Java Tutorials - Method References).

Так что вы просите тип выражения лямбды. Это ясно объясняется в JLS §15.27.3 (Type of a Lambda Expression).

Короче говоря, есть три Совместимость упомянутые:

  1. контекст Назначение
  2. контекст Призывание
  3. контекст Литье

тип лямбда-выражения или эталонный метод выводится с помощью компилятор. Поскольку теперь несколько контекстов могут (и должны) быть приняты во внимание, Java 8 поставляется с большими улучшениями для вывода типа.

Единственным ограничением для лямбда-выражений является то, что предполагаемый тип должен быть functional interface. Фактически, равные лямбда-выражения могут иметь разные типы в отношении их контекста.

5

От JLS, section 15.13.2, "Type of a Method Reference":

A Способ выражения ссылки совместим в контексте назначения, контекста вызова или литья контексте с целевой типа Т, если Т представляет собой функциональный тип интерфейса (§9.8) и выражение конгруэнтно с функцией типа основных целевого типа, полученным из T.

...

Если метод выражение ссылки совместит Wi го целевого типа T, , тогда тип выражения, U, является целевым типом земли, полученным от T.

В принципе, тип ссылки метода - это то, что ожидает от контекста. Независимо от контекста ссылка на метод действительно не имеет типа. Невозможно передать «исходную» ссылку на метод, а затем превратить ее в функцию или потребитель или что-то еще в какой-то более поздний момент.

1

Если у вас только есть ссылка на метод helloGreeter::makeGreetingFor, у него нет типа.

Если вы хотите, чтобы тип для ссылки метод, не назначая его или передать его в качестве аргумента (который назначает его к параметру), вы можете бросить его:

String greeting = 
    ((Function<String, String>)helloGreeter::makeGreetingFor) 
     .apply("Joe");