Могут ли члены лямбды получить доступ к целевому функциональному интерфейсу?

Я создал простой интерфейс с помощью 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);

    }
}