Anonymous Class vs Lambda
Before Java 8, the shortest way to pass behavior to a method was an anonymous class: a class with no name, declared and created in one expression (see "Anonymous Inner Class in Java"). Since Java 8, a lambda expression does the same job in far less code, but only for functional interfaces. They look similar, but they are not the same thing: they differ in what this means, what they can hold, and how they are compiled. In this lesson, you will compare them side by side.
Example: The Same Comparator, Two Ways
Let's see an example that sorts names by length with each.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class TwoWays {
public static void main(String[] args) {
List<String> names = new ArrayList<>(
List.of("Srihitha", "Navika", "Anamaneni", "Advitha"));
names.sort(new Comparator<String>() {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
});
System.out.println("Anonymous class: " + names);
names.sort((a, b) -> Integer.compare(b.length(), a.length()));
System.out.println("Lambda: " + names);
}
}Anonymous class: [Navika, Advitha, Srihitha, Anamaneni]
Lambda: [Anamaneni, Srihitha, Advitha, Navika]Explanation: The anonymous class needs the interface name, the method signature and @Override: six lines for one comparison. The lambda states only the parameters and the logic, in one line. The lambda here sorts longest first, just to show a different order.
The Meaning of this
Inside an anonymous class, this refers to the anonymous class object. Inside a lambda, this refers to the enclosing object, because a lambda isn't a separate object with its own identity:
public class ThisDemo {
private final String name = "outer ThisDemo";
@Override
public String toString() {
return name;
}
void run() {
Runnable anon = new Runnable() {
@Override
public void run() {
System.out.println("anonymous this: "
+ this.getClass().getSimpleName().isEmpty());
}
};
Runnable lambda = () -> System.out.println("lambda this: " + this);
anon.run();
lambda.run();
}
public static void main(String[] args) {
new ThisDemo().run();
}
}anonymous this: true
lambda this: outer ThisDemoExplanation: In the anonymous class, this is the anonymous object, whose class has no simple name, so getSimpleName() is empty. In the lambda, this is the ThisDemo object that created it, so its toString prints "outer ThisDemo".
Differences Between Anonymous Class and Lambda
| Anonymous class | Lambda expression | |
|---|---|---|
| Can implement | Any interface (any number of methods) or extend a class | Only a functional interface |
| Syntax | Verbose: new Type() { ... } | Short: (params) -> body |
Meaning of this | The anonymous object | The enclosing object |
| Fields and state | Can declare fields | Can't declare fields |
| Extra methods | Can add helper methods | Can't |
| Shadowing local variable names | Allowed | Not allowed |
| Compiled to | A separate .class file (Outer$1.class) | No extra class file; created at runtime with invokedynamic |
| Captured local variables | Must be effectively final | Must be effectively final |
Common Mistakes
Trying to use a lambda for an interface with two abstract methods. It doesn't compile; use an anonymous class or a named class.
Expecting this in a lambda to be the lambda. It's the surrounding object.
Declaring a lambda parameter with the same name as a local variable. It doesn't compile, while an anonymous class would allow it.
Interview Corner
What is the difference between an anonymous class and a lambda?
An anonymous class is a real unnamed class: it can implement any interface or extend a class, have fields and several methods, and inside it this refers to the anonymous object; the compiler generates a separate class file for it. A lambda can only implement a functional interface, has no fields or extra methods, treats this as the enclosing instance, can't shadow local variables, and is created at runtime through invokedynamic without a separate class file. Lambdas are shorter and usually more efficient.
Practice
- Easy: Rewrite an anonymous
Runnablethat prints "Navika" as a lambda. - Harder: Write an anonymous
Iterator<Integer>that counts from 1 to 5 using a field. Explain why it can't be written as a lambda.
Key Takeaways
Was this tutorial helpful?