Лямбда эта ссылка в java



Я хочу, чтобы преобразовать anonymous class до lambda expression. Но этот анонимный класс я использую this ключевое слово.



например, я написал это просто Observer/Observable шаблон :



import java.util.ArrayList;
import java.util.Collection;

public static class Observable {
private final Collection<Observer> notifiables = new ArrayList<>();

public Observable() { }

public void addObserver(Observer notifiable) { notifiables.add(notifiable); }
public void removeObserver(Observer notifiable) { notifiables.add(notifiable); }

public void change() {
notifiables.forEach(notifiable -> notifiable.changed(this));
}
}

public interface Observer {
void changed(Observable notifier);
}


и этот пример кода с анонимным классом (использование этого сайта) :



public class Main {

public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(new Observer() {
@Override
public void changed(Observable notifier) {
notifier.removeObserver(this);
}
});
observable.change();
}
}


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



public class Main {

public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(notifier -> { notifier.removeObserver(this); });
observable.change();
}
}


я получаю эту ошибку при компиляции :



Cannot use this in a static context and in a non `static` context



public class Main {
public void main(String[] args) {
method();
}

private void method() {
Observable observable = new Observable();
observable.addObserver(notifier -> {
notifier.removeObserver(this);
});
observable.change();
}
}


ошибка компиляции :



The method removeObserver(Main.Observer) in the type Main.Observable is not applicable for the arguments (Main)


Итак, мой вопрос : есть ли способ ссылаться на "лямбда-объект" с this ?

702   2  

2 ответов:

вы не можете ссылаться на this в лямбда-выражение. Семантика this был изменен, чтобы ссылаться только на экземпляр окружающего класса, из лямбды. Нет никакого способа ссылаться на лямбда-выражение this внутри лямбды.

проблема в том, что вы используете this на main() метод. Метод main является статическим и нет ссылки на объект, который представляет this.

при использовании this внутри экземпляр внутреннего класса, вы ссылаетесь на экземпляр внутреннего класса. Лямбда-выражение не является внутренним классом, this не ссылается на экземпляр лямбда-выражение. Он ссылается на экземпляр класса, в котором вы определяете лямбда-выражение. В вашем случае это будет экземпляр Main. Но так как вы находитесь в статическом методе, нет экземпляра.

это то, что ваша вторая ошибка компиляции говорит вам. Вы передаете экземпляр Main в ваш метод. Но ваша сигнатура метода требует экземпляра Observer.

обновление:

The спецификация языка Java 15.27.2 говорит:

в отличие от кода, появляющегося в анонимных объявлениях классов, значение имен и ключевых слов this и super, появляющихся в лямбда-теле, наряду с доступностью ссылочных объявлений, такие же, как и в окружающем контексте (за исключением того, что параметры лямбда ввести новые имена).

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

практически говоря, для лямбда-выражения необычно говорить о себе (либо называть себя рекурсивно или для вызова других методов), в то время как чаще всего требуется использовать имена для ссылки на вещи в классе enclosing, которые в противном случае были бы затенены ( это, toString ()). Если необходимо, чтобы лямбда-выражение ссылалось на себя (как будто через этой), вместо этого следует использовать ссылку на метод или Анонимный внутренний класс.

Способ 1

код change() метод выдает ConcurrentModificationException в любом случае.

public class Main {
    public static void main(String[] args) {
        Observable observable = new Observable();
        final Observer[] a = new Observer[1];
        final Observer o = er -> er.removeObserver(a[0]); // !!
        a[0] = o;
        observable.addObserver(o);
        observable.change();
    }
}
public class Observable {
    private final java.util.Collection<Observer> n
        = java.util.new ArrayList<>();
    public void addObserver(Observer notifiable) {
        n.add(notifiable);
    }
    public void removeObserver(Observer notifiable) {
        n.add(notifiable);
    }
    public void change() {
        for (final Observer o : n.toArray(new Observer[n.size()])) {
            o.changed(this);
        }
    }
}
public interface Observer {
    void changed(Observable notifier);
}

Способ 2

Я изменил changed(Observable) до changed(Observable, Observer) так что наблюдатель может справиться сам.

public class Main {
    public static void main(String[] args) {
        Observable observable = new Observable();
        final Observer o = (er, ee) -> er.removeObserver(ee); // !!
        observable.addObserver(o);
        observable.change();
    }
}
public class Observable {
    private final java.util.Collection<Observer> n
        = new java.util.ArrayList<>();
    public void addObserver(Observer notifiable) {
        n.add(notifiable);
    }
    public void removeObserver(Observer notifiable) {
        n.add(notifiable);
    }
    public void change() {
        for (final Observer o : n.toArray(new Observer[n.size()])) {
            o.changed(this, o);
        }
    }
}
public interface Observer {
    void changed(Observable notifier, Observer notifiee);
}

Comments

    Ничего не найдено.