Метод Java нельзя применить с лямбда-выражением

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

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"));
    }
}

person Smith Lo    schedule 10.09.2018    source источник


Ответы (3)


Разница в том, что вы пытаетесь переопределить реализацию 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();
person Naman    schedule 10.09.2018

Проблема

Метод 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 с помощью лямбды, было бы неоднозначно и неясно, какой метод будет представлять лямбда. Поэтому это запрещено (даже для абстрактных классов с одним абстрактным методом.)

person Andrew Tobilko    schedule 10.09.2018

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

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

Вот нормальное использование:

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

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

Таким образом, вам вообще не нужно создавать класс Eucalyptus.

person ernest_k    schedule 10.09.2018