Skip to content

Instantly share code, notes, and snippets.

@joseanpg
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joseanpg/dca2debc62b95d33ad4f to your computer and use it in GitHub Desktop.
Save joseanpg/dca2debc62b95d33ad4f to your computer and use it in GitHub Desktop.
Difference between Lambda Expression and Anonymous class.
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
interface SetObserver<E> {
void added(ObservableSet<E> set, E element);
}
public class ObservableSet<E> {
private final Set<E> set;
private final List<SetObserver<E>> observers = new ArrayList<SetObserver<E>>();
private void notifyElementAdded(E element) {
synchronized(observers) {
observers.forEach(observer -> observer.added(this, element));
}
}
public ObservableSet(Set<E> set) { this.set = set; }
public void addObserver(SetObserver<E> observer) {
synchronized(observers) {
observers.add(observer);
}
}
public boolean removeObserver(SetObserver<E> observer) {
synchronized(observers) {
return observers.remove(observer);
}
}
public boolean add(E element) {
boolean added = set.add(element);
if (added)
notifyElementAdded(element);
return added;
}
}
import java.util.HashSet;
public class ExampleObservableSet2 {
public static void main(String[] args) {
ObservableSet<Integer> observableSet = new ObservableSet<Integer>(new HashSet<Integer>());
observableSet.addObserver(
(ObservableSet<Integer> s, Integer e) -> {
System.out.println(e);
if (e == 23) s.removeObserver(this);//Broken!
}
);
for (int i = 0; i < 100; i++)
observableSet.add(i);
}
}
javac -Xdiags:verbose ExampleObservableSet2.java
ExampleObservableSet2.java:9: error: non-static variable this cannot be referenced from a static context
if (e == 23) s.removeObserver(this);
^
ExampleObservableSet2.java:9: error: method removeObserver in class ObservableSet<E> cannot be applied to given types;
if (e == 23) s.removeObserver(this);
^
required: SetObserver<Integer>
found: ExampleObservableSet2
reason: argument mismatch; ExampleObservableSet2 cannot be converted to SetObserver<Integer>
where E is a type-variable:
E extends Object declared in class ObservableSet
2 errors
import java.util.HashSet;
public class ExampleObservableSet2 {
public static void main(String[] args) {
ObservableSet<Integer> observableSet = new ObservableSet<Integer>(new HashSet<Integer>());
observableSet.addObserver(new SetObserver<Integer>() {
public void added(ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if (e == 23) s.removeObserver(this);
}
});
for (int i = 0; i < 100; i++)
observableSet.add(i);
}
}

JLS::15.27.2. Lambda Body

Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).

The transparency of this (both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.

Practically speaking, it is unusual for a lambda expression to need to talk about itself (either to call itself recursively or to invoke its other methods), while it is more common to want to use names to refer to things in the enclosing class that would otherwise be shadowed (this, toString()). If it is necessary for a lambda expression to refer to itself (as if via this), a method reference or an anonymous inner class should be used instead.

Difference between Lambda Expression and Anonymous class

One key difference between using Anonymous class and Lambda expression is the use of this keyword. For anonymous class ‘this’ keyword resolves to anonymous class, whereas for lambda expression ‘this’ keyword resolves to enclosing class where lambda is written.

Another difference between lambda expression and anonymous class is in the way these two are compiled. Java compiler compiles lambda expressions and convert them into private method of the class. It uses invokedynamic instruction that was added in Java 7 to bind this method dynamically. Tal Weiss has written a good blog on how Java compiles the lambda expressions into bytecode.

19
20
21
22
23
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList.forEach(ArrayList.java:1237)
at ObservableSet.notifyElementAdded(ObservableSet.java:16)
at ObservableSet.add(ObservableSet.java:39)
at ExampleObservableSet2.main(ExampleObservableSet2.java:13)
import java.util.HashSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
//DEADLOCK
//Using a Thread instance
public class ExampleObservableSet3 {
public static void main(String[] args) {
ObservableSet<Integer> observableSet = new ObservableSet<Integer>(new HashSet<Integer>());
observableSet.addObserver(new SetObserver<Integer>() {
public void added(final ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if (e == 23) {
Thread thread = new Thread(()->s.removeObserver(this)); //this references the instance
//of the anonymous SetObserver
try {
thread.start();
thread.join();
}
catch (InterruptedException ex) {
throw new AssertionError(ex.getCause());
}
}
}
});
for (int i = 0; i < 100; i++)
observableSet.add(i);
}
}
import java.util.HashSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
//DEADLOCK
//Using an ExecutorService
public class ExampleObservableSet3 {
public static void main(String[] args) {
ObservableSet<Integer> observableSet = new ObservableSet<Integer>(new HashSet<Integer>());
observableSet.addObserver(new SetObserver<Integer>() {
public void added(final ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if (e == 23) {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(()->{s.removeObserver(this);}).get(); //this references the instance
//of the anonymous SetObserver
}
catch (ExecutionException ex) {
throw new AssertionError(ex.getCause());
}
catch (InterruptedException ex) {
throw new AssertionError(ex.getCause());
}
finally {
executor.shutdown();
}
}
}
});
for (int i = 0; i < 100; i++)
observableSet.add(i);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment