From Anonymous Classes to Lambdas
From Anonymous Classes to Lambdas
Java has always let you pass behaviour around as an object. Long before lambdas existed, the standard technique was an anonymous class — an unnamed implementation of an interface (or abstract class) written inline, right where it was needed. Lambdas do not add a new concept; they remove the ceremony around that same idea.
The Anonymous-Class Pattern
Suppose you want to sort a list of strings by length. Before Java 8 you would write:
This works perfectly. But look at how many lines it takes to express one simple idea: compare by length. You have to:
- Write
new Comparator<String>() { }to create the anonymous class. - Write the
@Overrideannotation and the full method signature. - Then — finally — write the one line of logic you actually cared about.
This pattern is sometimes called boilerplate: code that is structurally required but communicates no real intent. The ratio of ceremony to logic is about 5:1.
Enter Lambdas
A lambda expression is a compact way to write exactly the same anonymous class — when the interface has exactly one abstract method. Here is the same sort rewritten with a lambda:
One line. No class declaration, no annotation, no method signature. The compiler infers the types of a and b from the context (Comparator<String> is expected, so both must be String).
Another Common Case: Runnable
Runnable is one of the oldest single-method interfaces in Java. With an anonymous class:
With a lambda:
The parentheses () indicate zero parameters. The body is the single statement after the arrow.
What the Compiler Sees
The compiler can replace an anonymous class with a lambda only when the interface is a functional interface — one that declares exactly one abstract method. Comparator, Runnable, and dozens of other interfaces in the JDK qualify. The optional @FunctionalInterface annotation lets you declare your own:
Both variables hold something that responds to greet(String). The lambda is just a shorter way to express it.
Why This Matters
Removing boilerplate is not purely cosmetic. When the noise is gone, the intent — what the code actually does — becomes the only thing a reader sees. This shift unlocks a style of programming where small pieces of behaviour are passed around, combined, and composed just as easily as data. Every lesson in this tutorial builds on that insight.
-> separates the inputs (left side) from the result (right side). Train yourself to read (a, b) -> Integer.compare(a.length(), b.length()) as "given a and b, produce Integer.compare of their lengths". The types are just noise that the compiler handles for you.
Summary
Anonymous classes let you pass behaviour as an object but require a lot of structural noise. Lambdas express the same idea with a concise (parameters) -> body syntax, provided the target type is a functional interface. The rest of this tutorial explores the rich set of functional interfaces the JDK provides, and the powerful ways lambdas can be composed.