Lambda Expressions & Functional Interfaces
java2-2 used String::length and Comparator.comparing() without pausing on what makes them possible. This chapter is that pause — and a genuine reveal about what a lambda actually is under the hood.
Functional Interfaces — The Prerequisite
A functional interface is an interface with exactly one abstract method — a Single Abstract Method, or SAM. This directly builds on java1-6's own interface material; default methods don't count against the limit, only abstract ones do. @FunctionalInterface is optional, but when present, the compiler enforces the one-abstract-method rule and flags a violation immediately.
Lambda Expressions — Syntax
A lambda's parameter types are inferred from the functional interface's own method signature — Calculator already says both parameters are int, so the lambda doesn't repeat it.
Lambdas Are Sugar Over Existing OOP
Here's the reveal: Calculator add = (a, b) -> a + b; is really instantiating an anonymous implementation of Calculator's single method — the compiler generates essentially the same thing as the anonymous-inner-class version shown above. Nothing genuinely new exists in the language's object model; a lambda is compact syntax for a pattern that was already fully expressible in java1-6's own interface system. This is a real, direct parallel to cpp2-7's own reveal — std::cout << turned out to have been using cpp1-6's own operator-overload mechanism the entire time; here, every lambda turns out to have been using java1-6's own interface-implementation mechanism the entire time.
Built-in Functional Interfaces
java.util.function supplies ready-made functional interfaces for the shapes that come up constantly — Function<T,R>, Predicate<T>, Consumer<T>, Supplier<T> — so most code never needs to declare a custom one at all.
Method References
Class::method is shorthand for a lambda that does nothing but call an existing method — exactly what powered java2-2's own String::length sort. It's the same mechanism as any other lambda, just with the boilerplate parameter-passing removed since the method reference already implies it.
| Concept | C++ (cpp1-6 / cpp2-7) | Java |
|---|---|---|
| The underlying mechanism | operator() overload (a "functor") | SAM interface implementation |
| The "reveal" chapter | cpp2-7 — cout << was always operator<< | this chapter — a lambda was always an interface impl |
| Compact syntax added later | C++11 lambdas, sugar over the same idea | Java 8 lambdas, sugar over the same idea |
Function, Predicate, Consumer, and Supplier already cover the overwhelming majority of shapes a lambda needs — a custom functional interface is worth writing only when none of the standard shapes genuinely fit.
final keyword written explicitly. This is stricter than a JavaScript closure, which can freely mutate a captured variable; attempting the same in a Java lambda simply fails to compile.
Coding Challenges
Write a functional interface StringTransformer with one abstract method transform(String s), then implement it once as an anonymous inner class and once as a lambda that both uppercase a string, showing both produce the same result.
📄 View solutionWrite code using Predicate<Integer> to check whether a number is even, and Function<Integer, Integer> to square a number, applying both to a list of integers and printing the results.
📄 View solutionWrite a lambda that captures a local int variable, then attempt to reassign that variable after the lambda is defined. Show the resulting compile error and explain why it happens in terms of effectively final.
📄 View solutionChapter 3 Quick Reference
- A functional interface has exactly one abstract method (a SAM); default methods don't count, per java1-6
- A lambda is compact syntax for an anonymous implementation of a functional interface's single method — nothing new in the object model
- Genuinely comparable to cpp2-7's own reveal: cout << was always operator<<, just as every lambda is always an interface implementation
- java.util.function supplies Function/Predicate/Consumer/Supplier for the common shapes, avoiding custom interfaces
- Class::method is shorthand for a lambda that just calls an existing method
- Captured local variables must be effectively final — stricter than JavaScript's mutable closures
- Next chapter: the Streams API — functional-style data processing built on these same functional interfaces