Syntactically and semantically, how does a lambda differ from the anonymous inner class it appears to replace?
answer
- lambda = no new/name/signature, just params -> body
- lambda targets functional interface only; anon class can extend a class / add methods
- this in a lambda = enclosing instance; in anon class = the anon object
- lambda adds no scope (can't shadow); anon class has its own scope
- lambda compiles to invokedynamic, anon class to a separate .class
basics
~20 sA lambda is shorter — just params -> body with no new, class name, or method signature. It can only implement a single-method interface, while an anonymous class can extend a class or add multiple methods. Also, this inside a lambda means the enclosing object, not the lambda itself.
solid answer
~50 sSyntactically, a lambda drops all the ceremony of an anonymous class: no `new InterfaceName() { public ... method() { ... } }`, just `params -> body`, with parameter types inferred via target typing. Semantically there are real differences. A lambda can only target a **functional interface** (one abstract method); an anonymous class can extend a class or implement an interface with several methods. Inside a lambda, `this` refers to the **enclosing instance**, and the lambda introduces **no new scope** — so it cannot shadow enclosing local variables; an anonymous class creates its own `this` and its own scope. Both capture only **effectively final** locals. Implementation-wise, lambdas are compiled to an `invokedynamic` bootstrap (no extra `.class` file per lambda in the common case), whereas each anonymous class generates a separate `Outer$1.class`. Lambdas are the idiomatic choice for single-method behavior; anonymous classes remain necessary for stateful or multi-method implementations.
code
java · 9 linesclass Demo {
String name = "demo";
Runnable asLambda = () -> System.out.println(this.name); // this == Demo instance
Runnable asAnon = new Runnable() {
public void run() {
System.out.println(Demo.this.name); // 'this' is the anon Runnable; outer via Demo.this
}
};
}go deeper
Knows a lambda is a shorter way to write an anonymous class for a single-method interface.
Can list the this/scope differences and the single-method restriction, and choose the right construct for a task.
Explains the no-new-scope/shadowing rule, effectively-final capture for both, and the invokedynamic compilation difference.
Reasons about performance and class-loading implications of invokedynamic lambdas at scale and sets conventions for when anonymous classes are still warranted.
## The surface: syntax Before Java 8, passing behavior meant an **anonymous inner class**: ```java button.addListener(new Listener() { public void onClick(Event e) { handle(e); } }); ``` A lambda collapses this to: ```java button.addListener(e -> handle(e)); ``` Gone are `new`, the interface name, the method signature, and the braces. The parameter type of `e` is inferred from the target functional interface. This is pure boilerplate reduction. ## Difference 1 — what they can implement - A **lambda** can only stand for a **functional interface** (exactly one abstract method). It cannot extend a class, and cannot implement an interface that has two or more abstract methods. - An **anonymous class** can extend a concrete or abstract **class**, implement a multi-method interface, and declare **extra fields and methods**. For anything stateful or multi-method, you still need an anonymous (or named) class. ## Difference 2 — the meaning of `this` This is the classic interview trap. - In an **anonymous class**, `this` refers to the **anonymous instance itself**. To reach the enclosing object you write `Outer.this`. - In a **lambda**, there is **no new `this`** — `this` is the **enclosing instance**. A lambda is not a separate object scope; it lexically belongs to its surroundings. ```java class Demo { Runnable lambda = () -> System.out.println(this); // 'this' == the Demo instance Runnable anon = new Runnable() { public void run() { System.out.println(this); } // 'this' == the anonymous Runnable }; } ``` ## Difference 3 — scope and shadowing A lambda **introduces no new scope**: its parameters and body live in the enclosing scope, so a lambda parameter **cannot reuse the name** of an enclosing local variable (that would be a compile error). An anonymous class has its **own** scope, so it *can* shadow enclosing names. ## Difference 4 — variable capture (shared trait, worth stating) Both capture local variables, and both require captured locals to be **final or effectively final** (assigned once). Neither can mutate a captured local. They capture by value for primitives/references; you work around the restriction with a holder object or array if you truly need mutation (rarely advisable). ## Difference 5 — compilation and runtime - An **anonymous class** generates a **separate class file** (`Outer$1.class`) at compile time; an instance is created with `new`. - A **lambda** is compiled to an **`invokedynamic`** call site backed by the `LambdaMetafactory`; the JVM synthesizes the implementation lazily at first use. In the common case this avoids a per-lambda `.class` file and can be cheaper (e.g. a stateless lambda may be a singleton). This is an implementation detail, but it explains why lambdas don't bloat the class count. ## When to use which - **Lambda:** any single-method behavior — comparators, runnables, stream operations, callbacks. Idiomatic and concise. - **Anonymous class:** you need to extend a class, implement multiple methods, hold per-instance state with extra fields, or you genuinely want a distinct `this`/scope. ## Summary table | Aspect | Lambda | Anonymous class | |---|---|---| | Target | functional interface only | class or any interface | | `this` | enclosing instance | the anonymous instance | | New scope | no | yes (can shadow) | | Extra members | no | fields + methods allowed | | Capture | effectively final | effectively final | | Compiled to | `invokedynamic` | separate `.class` file |
- What does `this` refer to inside a lambda versus inside an anonymous class?Inside a lambda, `this` is the enclosing instance (the lambda creates no new `this`). Inside an anonymous class, `this` is the anonymous object itself, and you reach the outer instance via `Outer.this`.
- Give a case where you must use an anonymous class instead of a lambda.When you need to implement an interface with more than one abstract method, extend a class, or add extra fields/methods/state — a lambda can only stand for a single-method interface with no extra members.
saying these in an interview costs you the question
- Saying `this` in a lambda refers to the lambda object
- Thinking a lambda can implement a two-method interface
- Claiming a lambda can shadow an enclosing local variable name
- Believing each lambda generates its own anonymous class file