☕ Java

Lambda-Funktionen und funktionaler Stil in Java: eine ausführliche Anleitung

What is it and why? (a real-life analogy)

Imagine you are a head chef in a restaurant. You have junior cooks who can execute simple commands: "peel the potato", "chop the onion", "wash the dishes". Each cook is a method (function). Everything is clear and familiar.

But suddenly an important guest arrives and says: "I need a special dish. I want you to invent a new way of cutting vegetables right now — spiralized — and apply it only to my salad." You cannot train all the cooks in advance for this — the method is needed once, right now.

This is where lambda functions come to the rescue. It's like writing an instruction on a napkin: "Take a carrot and cut it into a spiral, like this..." — and handing it to the cook. He reads it, does it, and throws the napkin away. You didn't need to create a new cook with a name, you didn't need to write this method in the recipe book. You simply passed behavior (an action) as an object.

The essence of lambda: it is an anonymous (nameless) function that can be created on the fly and passed to another method or stored in a variable. It makes code shorter, cleaner, and more expressive.

Why is this needed in real programming? Imagine you have a list of numbers, and you need to:

  • filter only even numbers;
  • multiply each number by 2;
  • sort in descending order;
  • print the result.

Without lambdas, you would have to write separate classes with methods, create anonymous inner classes (which is cumbersome). With lambdas, this is done in 3-4 lines. Lambdas are a step towards the functional style, where we think not "how to do it", but "what to do".

Theory: how it works internally

To understand lambdas, you need to grasp the key concept — the functional interface. This is an interface that has exactly one abstract method. For example, Runnable (method run()), Comparator (method compare()), ActionListener (method actionPerformed()).

A lambda expression is simply a concise form of implementing that single method. The Java compiler looks at the context: if a functional interface is expected, it understands that the lambda is its implementation.

Internally, Java turns the lambda into a special object. But it does this cleverly: it does not create a separate class file for each lambda (as it does for anonymous classes). Instead, it uses invokedynamic — a bytecode instruction that creates the implementation on the fly, efficiently and quickly. This is one of the reasons lambdas work faster than anonymous classes.

A lambda expression consists of three parts:

  1. Parameter list in parentheses: (int x, int y)
  2. Arrow: ->
  3. Body: an expression or a block of code in curly braces

If the body is a single expression, curly braces and return are not needed. If the body is a block, both braces and return are needed (if the method returns a value).

Important: a lambda does not have its own name, does not belong to a class, and cannot have its own fields. It simply implements the method of a functional interface.

Syntax in Java: all forms and variants

Let's look at all possible forms of writing lambda expressions using the functional interface Comparator<Integer> (method int compare(Integer a, Integer b)) as an example.

Form Example When to use
Full (with types) (Integer a, Integer b) -> { return a - b; } When you need to explicitly specify types (rare)
With type inference (a, b) -> { return a - b; } Standard case, types are taken from the context
Single expression (without return) (a, b) -> a - b When the body is a single expression (most common case)
Single parameter (without parentheses) a -> a * 2 When there is exactly one parameter, parentheses can be omitted
No parameters () -> System.out.println("Hello") For interfaces like Runnable
Method reference Integer::compare When the lambda simply calls an existing method

Method references are an even more concise form. If your lambda looks like (x) -> SomeClass.someMethod(x), it can be replaced with SomeClass::someMethod. There are four types of method references:

Type Syntax Example
Static method ClassName::staticMethod Integer::parseInt
Instance method of a specific object object::instanceMethod list::add
Instance method of an arbitrary object ClassName::instanceMethod String::length
Constructor ClassName::new