Мне сказали преобразовать лямбду с параметризованным конструктором в ссылку на метод

Допустим, у меня есть класс Gizmo с конструктором, который принимает строку. Допустим, я хочу преобразовать List<String> в List<Gizmo>.

Я мог бы написать:

List<String> strings = new ArrayList<>();
List<Gizmo> gizmos = strings
        .stream()
        .map(str -> new Gizmo(str))
        .collect(Collectors.toList());

Теперь проблема в том, что IntelliJ сказал мне, что я могу заменить лямбду ссылкой на метод. Дело в том, что я почти уверен, что ссылки на методы не могут принимать параметры.


person AaronF    schedule 18.05.2017    source источник
comment
comment
Афаик, если IntelliJ говорит вам, что вы можете это сделать, вы можете сказать IntelliJ сделать это. Затем вы можете проверить результат рефакторинга.   -  person Holger    schedule 18.05.2017


Ответы (4)


Я думаю, что InteliJ означает замену

.map(str -> new Gizmo(str))

с

.map(Gizmo::new)

который является ссылкой на конструктор. См. подробное объяснение здесь.

person Sergey Kalinichenko    schedule 18.05.2017
comment
И это передает строку в конструктор. Я этого не знал. Предполагается, что это было только для пустых конструкторов. Спасибо. - person AaronF; 18.05.2017

Теперь проблема в том, что IntelliJ сказал мне, что я могу заменить лямбду ссылкой на метод.

это просто означает, что вы можете изменить это:

.map(str -> new Gizmo(str))

к этому:

.map(Gizmo::new)

вы можете прочитать больше о справочнике по методу конструктора.

person Ousmane D.    schedule 18.05.2017
comment
Вау, мы использовали ту же ссылку для объяснения ссылки на конструктор!!! - person Sergey Kalinichenko; 18.05.2017
comment
какое совпадение !! ^^. - person Ousmane D.; 18.05.2017

Также есть небольшая оптимизация при использовании ссылки на метод вместо лямбда-выражения.

Лямбда-выражения обезвреживаются до статического/экземплярного метода (зависит от того, действительно ли это lambda/clojure), но ссылки на методы - нет.

В вашем случае при использовании лямбда-выражения (t -> new Gizmo(t)) компилятор сгенерирует дополнительный метод в вашем классе; это будет выглядеть так:

  private static Gizmo lambda$main$0(String s) {
      return new Gizmo(s);   
  }

В случае ссылки на метод (ссылка на конструктор) она не будет присутствовать.

person Eugene    schedule 18.05.2017

Ссылка на метод — это просто ссылка на метод, независимо от того, сколько аргументов у метода есть на самом деле. Ссылка на конструктор — это просто частный случай ссылки на метод, который ссылается на конструктор.

Предположим, у вас есть класс Person:

public class Person {

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age  age;
    }

    // getters, setters
}

Теперь также предположим, что у вас есть BiFunction<String, Integer, Person> который сопоставляет аргументы имени и возраста с экземплярами класса Person:

BiFunction<String, Integer, Person> personCreator = 
    (String name, Integer age) -> new Person(name, age);

Или, поскольку типы параметра лямбда-выражения напрямую определяются компилятором:

BiFunction<String, Integer, Person> personCreator = (name, age) -> new Person(name, age);

Вы можете использовать эту функцию с двумя аргументами следующим образом:

Person joe = personCreator.apply("Joe", 25);

Вы заметили, что тип и порядок параметров в лямбда-выражении (name, age) совпадают с параметрами в конструкторе? Это означает, что вместо этого мы можем использовать ссылку на метод:

BiFunction<String, Integer, Person> personCreator = Person::new;

И это будет работать, как и ожидалось:

Person jane = personCreator.apply("Jane", 23);

Это просто для того, чтобы показать вам, что количество аргументов не имеет значения при использовании ссылок на методы. Все, что должно совпасть, — это сигнатура единственного абстрактного метода функционального интерфейса (в данном случае BiFunction.apply) с сигнатурой конструктора.

Если вы хотите узнать больше о ссылках на методы, перейдите к разделу о методах. ссылки в Учебнике по Java.

person fps    schedule 18.05.2017