Подтвердить что ты не робот

Код ведет себя по-другому после преобразования анонимного класса в лямбда

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

class ItemList {
    interface OnClickListener {
        void onClick();
    }
    OnClickListener current;
    OnClickListener newListener(final int n) {
        return current = new OnClickListener() {
            public void onClick() {
                if (this == current)
                    System.out.println("doing something special (item #"+n+")");
                System.out.println("selected item #" + n);
            }
        };
    }
    public static void main(String[] args) {
        ItemList l = new ItemList();
        OnClickListener ocl1 = l.newListener(1);
        OnClickListener ocl2 = l.newListener(2);
        OnClickListener ocl3 = l.newListener(3);
        ocl1.onClick();
        ocl2.onClick();
        ocl3.onClick();
    }
}

Работает так, как ожидалось:

$ javac ItemList.java && java ItemList
selected item #1
selected item #2
doing something special (item #3)
selected item #3

Теперь я меняю его на использование лямбда вместо анонимного класса:

class ItemList {
    interface OnClickListener {
        void onClick();
    }
    OnClickListener current;
    OnClickListener newListener(final int n) {
        return current = () -> {
            if (this == current)
                System.out.println("doing something special (item #"+n+")");
            System.out.println("selected item #" + n);
        };
    }
    public static void main(String[] args) {
        ItemList l = new ItemList();
        OnClickListener ocl1 = l.newListener(1);
        OnClickListener ocl2 = l.newListener(2);
        OnClickListener ocl3 = l.newListener(3);
        ocl1.onClick();
        ocl2.onClick();
        ocl3.onClick();
    }
}

Но теперь он больше не делает ничего особенного в последнем элементе? Зачем? Работает ли == по-разному с лямбдами? Я думал, что это была ошибка в ретроальбанде, но этот пример работает на простом JDK8, и это все еще происходит.

$ javac A.java && java A
selected item #1
selected item #2
selected item #3
4b9b3361

Ответ 1

this внутри lambda не означает то же, что и this внутри экземпляра анонимного класса.

Внутри lambda он относится к охватывающему классу.

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

Внутри экземпляра анонимного класса он ссылается на текущий объект

Внутри метода экземпляра или конструктора это ссылка на текущий объект - объект, метод или конструктор которого вызывается

Итак, в выражении лямбда this == current никогда не является истинным, поскольку он сравнивает экземпляр класса ItemList с лямбда-выражением типа OnClickListener.