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
Anonymous class is an inner class without a name, which means that we can declare and instantiate class at the same time. A lambda expression is a short form for writing an anonymous class. By using a lambda expression, we can declare methods without any name.
Since the most common use of Anonymous class is to provide a throwaway, stateless implementation of abstract class and interface with a single function, those can be replaced by lambda expressions, but when you have a state field or implementing more than one interface, you cannot use lambdas to replace the anonymous ...
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With