Code behaves different after converting anonymous class to lambda

anonymous-inner-class, java, java-8, lambda

Solution

`this` inside lambda doesn't mean the same as `this` inside an anonymous class instance.

Inside a lambda it refers to the enclosing class.

...the lambda expression does not introduce a new level of scoping. Consequently, you can directly access fields, methods, and local variables of the enclosing scope. ... To access variables in the enclosing class, use the keyword this. ...

Inside an instance of an anonymous class, it refers to the current object

Within an instance method or a constructor, this is a reference to the current object — the object whose method or constructor is being called

That's why in the lambda expression, `this == current` is never true, since it compares an instance of class `ItemList` with a lambda expression of type `OnClickListener`.

Problem

I'm trying to refactor this code to use a lambda instead of anonymous class. It's a simple list of items in a GUI. I register a different listener to each item, and the last item created does something special when clicked. ``` 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(); } } ``` It works as expected: ``` $ javac ItemList.java && java ItemList selected item #1 selected item #2 doing something special (item #3) selected item #3 ``` Now I change it to use a lambda instead of anonymous class: ``` 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(); } } ``` But now it no longer does anything special on the last item? Why? Does `==` work differently with lambdas? I thought it was a bug in retrolambda at first, but this example is running on plain JDK8 and it still happens. ``` $ javac A.java && java A selected item #1 selected item #2 selected item #3 ```

Original source