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
  • this inside a lambda means the enclosing instance — not the lambda
  • Prefer lambdas to anonymous classes (EJ 42); keep them short — a line or three
From ceremony to intent
// 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));            // clearest

Forms: 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).

Sources
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 6.2 — Lambda Expressions
  • Effective Java (3rd ed.)Item 42
  • Learning Java (6th ed.)Ch. 5, 7 — Lambdas