Метод 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
вообще.