Могут ли члены лямбды получить доступ к целевому функциональному интерфейсу?
Я создал простой интерфейс с помощью java8. При этом он содержит один метод и один метод по умолчанию.
interface Lambda{
default void dummy(){
System.out.println("Call this..");
}
void yummy();
}
Я пытаюсь использовать эти два метода, используя исторический способ, например
public class DefaultCheck {
public static void main(String[] args) {
DefaultCheck check = new DefaultCheck();
check.activate(new Lambda() {
@Override
public void yummy() {
dummy();
}
});
}
void activate(Lambda lambda){
lambda.yummy();
}
}
Теперь я пытаюсь реализовать ту же самую вещь, используя лямбда-выражение, получая ошибку, например `dummy is undefined`
check.activate(() -> {
dummy();
});
Может ли кто-нибудь предложить, как реализовать этот сценарий, используя выражение Lambda?
Ответы
Ответ 1
Это невозможно сделать.
JLS 15.27.2 описывает это:
В отличие от кода, появляющегося в объявлениях анонимного класса, значение имена и это и супер ключевые слова, появляющиеся в лямбда-теле, наряду с доступностью ссылочных объявлений, являются одинаковыми как в окружающем контексте (за исключением того, что параметры лямбда вводят новые имена).
Прозрачность этого (как явного, так и неявного) в теле лямбда-выражения - то есть, рассматривая его так же, как в окружающий контекст - обеспечивает большую гибкость для реализаций и препятствует тому, чтобы значение неквалифицированных имен в теле было в зависимости от разрешения перегрузки.
Практически говоря, для выражения лямбды необычно говорить о себе (либо называть себя рекурсивно , либо вызывать его другие методы), в то время как более распространено желание использовать имена для ссылки к вещам в окружающем классе, которые иначе были бы затенены (это, toString()). Если для лямбда-выражения необходимо ссылаться на себя (как бы через это), ссылку на метод или анонимную Вместо этого следует использовать внутренний класс.
Ответ 2
Внутренняя реализация класса работает, поскольку код вызывается так, как если бы вы закодировали:
check.activate(new Lambda() {
@Override
public void yummy() {
this.dummy();
}
});
Наша проблема заключается в том, что лямбды не вводят новую область. Итак, если вы хотите, чтобы ваша лямбда могла ссылаться на себя, вы можете уточнить свой @FunctionalInterface, чтобы его функциональный метод принимал сам и его требуемые параметры:
check.activate(this_ -> this_.dummy());
где Lambda определяется как:
@FunctionalInterface
public interface Lambda {
void yummy(Lambda this_);
default void yummy() {
yummy(this);
}
default void dummy(){
System.out.println("Call this..");
}
}
Ответ 3
Если я правильно понимаю. Вы пытаетесь вызвать метод по умолчанию в интерфейсе через реализацию лямбда. Я думаю, это можно сделать.
@FunctionalInterface
interface Value
{
String init(Value a);
default String add(String b)
{
return "added content "+b;
}
default String getResult()
{
String c = init(this);
return c;
}
}
public class Main
{
public static void main(String[] args)
{
Value v = a -> a.add("inpout"); // here I am calling add method in Value interface.
String c = v.getResult();
System.out.println(c);
}
}