BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Generics and functional

Java language

Lambdas and functional interfaces

A lambda is a short, nameless function you can pass around: x -> x * 2.

Learn these first

At a glance

Mental model

Instead of writing a whole recipe card and naming it, you hand over a sticky note with the one step ("double it") for the other person to apply wherever they need.

What happens, in order
  1. 1The arrow separates the parameters from the body: (a, b) -> a + bA body with one expression returns it; a block in braces needs return.
  2. 2The target is a functional interface such as Function<T,R> (one input, one output), Predicate<T> (returns boolean), Consumer<T> (returns nothing) or Supplier<T> (no input, returns a value)The compiler infers the types from the context.
  3. 3A lambda can read local variables from the surrounding method, but only if they are effectively final (never reassigned)This is why you cannot increment a local counter from inside a lambda.
Remember
Watch out
Mutating a captured local variable (compile error) and "fixing" it with a one-element arrayDoing blocking or stateful work in a stream lambdaPutting long logic in a lambda instead of a named method
Example (highlighted lines explain it)
List<String> names = users.stream().map(u -> u.getName()).toList();
Read the full explanation (about 2 min)

A lambda is a short, nameless function you can pass around: x -> x * 2. It works wherever Java expects an interface with exactly one abstract method.

A mental model

Instead of writing a whole recipe card and naming it, you hand over a sticky note with the one step ("double it") for the other person to apply wherever they need.

How it works

The arrow separates the parameters from the body: (a, b) -> a + b. A body with one expression returns it; a block in braces needs return.

The target is a functional interface such as Function<T,R> (one input, one output), Predicate<T> (returns boolean), Consumer<T> (returns nothing) or Supplier<T> (no input, returns a value). The compiler infers the types from the context.

A lambda can read local variables from the surrounding method, but only if they are effectively final (never reassigned). This is why you cannot increment a local counter from inside a lambda.

Going deeper

A lambda is not a new kind of object with its own this: this inside it means the enclosing class. For a named behaviour with its own state, use a class instead.

Lambdas hide control flow: an exception thrown inside is thrown at the place the lambda is called (for example in the middle of a stream pipeline). Checked exceptions cannot be thrown from the standard functional interfaces, so wrap them.

Avoid side effects inside lambdas that run in parallel streams or on other threads; captured mutable state becomes a data race.

Under the hood

The compiler turns a lambda into a private synthetic method and uses invokedynamic with LambdaMetafactory to create the interface instance at first use. Non-capturing lambdas are cached as a single instance.

Common mistakes

  • Mutating a captured local variable (compile error) and "fixing" it with a one-element array.
  • Doing blocking or stateful work in a stream lambda.
  • Putting long logic in a lambda instead of a named method.

How Unravel recognises it

When you paste code, Unravel looks for these signs of lambdas and functional interfaces. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Builds on this

Frequently asked questions

What is Lambdas and functional interfaces?

A lambda is a short, nameless function you can pass around: x -> x * 2. It works wherever Java expects an interface with exactly one abstract method.

What are the most common mistakes with Lambdas and functional interfaces?

Mutating a captured local variable (compile error) and "fixing" it with a one-element array. Doing blocking or stateful work in a stream lambda. Putting long logic in a lambda instead of a named method.

How can I see Lambdas and functional interfaces in real code?

Paste your own Java into Unravel and it will point out where lambdas and functional interfaces appears, explain how it works at the detail level you choose, and draw the flow of the code around it.