Метод Java не может применяться с выражением Lambda

Я смотрел и читал https://caveofprogramming.com/java/whats-new-in-java-8-lambda-expressions.html, и я слежу за тем же шаблоном, который я сделал для объекта runner, который отлично работает.

Runner runner = new Runner();
runner.run(() -> System.out.println("Print from Lambda expression"));

Затем я пытаюсь создать простой интерфейс и класс, чтобы применить то, что я узнал. Я просто хочу заменить анонимный класс выражением лямбда. Мое понимание - выражение лямбда - это более короткий код для анонимного класса и улучшенная читаемость.

Итак, я попытался инициировать другой экземпляр с именем eucalyptus1 и попытаться @Override метод grow(), но в сообщении об ошибке IDE сказано:

grow() в com.smith.Eucalyptus не может быть применен к (lambda expression)

Может ли кто-нибудь указать мне, что я неправильно понял здесь?

Код ниже:

// a simple interface
interface Plant {
    public void grow();
}

// apply interface to class
class Eucalyptus implements Plant {
    @Override
    public void grow() {
        System.out.println("This is from Eucalyptus");
    }
}

public class Main {
    public static void main(String[] args) {

        // Create an instance of Eucalyptus
        Eucalyptus eucalyptus = new Eucalyptus();
        eucalyptus.grow();

        // Anonymous class Myrtle from Plant interface
        Plant myrtle = new Plant() {
            @Override
            public void grow() {
                System.out.println("This was running from anonymous class from Plant Interface");
            }
        };

        myrtle.grow();

        // Try to create a lambda expression from Plant interface
        // and override grow() method
        // by print ("This was running from Lambda expression")

        // this won't work. why?
        Eucalyptus eucalyptus1 = new Eucalyptus();
        eucalyptus1.grow(() -> System.out.println("This from Lambda expression"));
    }
}

Ответ 1

Разница в том, что вы пытаетесь переопределить реализацию Eucalyptus который является классом, реализующим интерфейс.

Eucalyptus eucalyptus1 = new Eucalyptus();
eucalyptus1.grow(() -> System.out.println("This from Lambda expression")); 
^__  // you cannot override a method using an instance of a class which is just an implementation of the interface

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


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

//Anonymous class Myrtle from Plant interface
Plant myrtle = new Plant() {
          @Override
          public void grow() {
               System.out.println("This was running from anonymous class from Plant Interface");
          }
};
myrtle.grow();

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

Plant lambdaRep =  () -> System.out.println("This is running via lambda from Plant Interface");
lambdaRep.grow();

Ответ 2

проблема

Метод grow не принимает никаких параметров, поэтому вы получили ошибку компиляции.

объяснение

Сам лямбда () → System.out.println("This from Lambda expression") может представлять экземпляр Plant (не Eucalyptus *):

Plant plant = () -> System.out.println("This from Lambda expression");

Попробуйте создать лямбда-выражение из интерфейса Plant и переопределить метод grow(), напечатав "This was running from Lambda expression".

Здесь есть небольшое недоразумение. Лямбда не должна переопределять метод, чтобы обеспечить метод, основанный на типе @FunctionalInterface.


* Если бы вы определили объект Eucalyptus лямбдой, было бы двусмысленно и неясно, какой метод будет представлять лямбда. Поэтому он запрещен (даже для абстрактных классов с одним абстрактным методом).

Ответ 3

Ваше использование выражения лямбда здесь неверно.

Для реализации интерфейса вы используете лямбда-выражения. В этом случае вы будете обеспечивать реализацию Plant с использованием выражения лямбда, а не вызов этого метода интерфейса с помощью выражения лямбда:

Здесь нормальное использование:

Plant eucalyptus1 = () -> System.out.println("This from Lambda expression");
eucalyptus1.grow(); // Prints "This from Lambda expression"

Другими словами, поскольку у вас есть функциональный интерфейс, вы должны избегать создания классов, реализующих его (анонимно или нет).

Поэтому вам не нужно создавать класс Eucalyptus вообще.