Functional Programming & Streams
Lambda Expressions
A lambda is a compact block of code you pass around for deferred execution —
(params) -> body. It implements a functional interface, captures effectively-final variables, and (unlike an anonymous class) has no identity of its own.- Syntax:
(String a, String b) -> a.length() - b.length(); types usually inferred - A lambda's type is always a functional interface (one abstract method)
- Captured local variables must be effectively final
thisinside a lambda means the enclosing instance — not the lambda- Prefer lambdas to anonymous classes (EJ 42); keep them short — a line or three
// The unit of behavior: "compare two strings by length"
Arrays.sort(words, new Comparator<String>() { // 2004
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
});
Arrays.sort(words, (a, b) -> Integer.compare(a.length(), b.length())); // lambda
Arrays.sort(words, Comparator.comparingInt(String::length)); // clearestForms: zero params () -> 42; one param, parens optional w -> w.length(); block body with return when one expression isn't enough. The compiler infers parameter types from the target functional interface — write them only when it helps the reader.
Capture: lambdas may read local variables of the enclosing scope if they are effectively final (never reassigned). This prevents data races on stack variables and keeps capture semantics simple — mutation belongs in the object the lambda operates on, not in captured locals. Instance fields have no such restriction (the lambda captures this).