Java Lambda Expressions

Java lambda expressions are short, anonymous functions you can pass around like values. Added in Java 8, they make code that sorts, filters or reacts to events far more concise.

Lambda Syntax

  • (parameters) -> expression, for example (a, b) -> a + b
  • A single parameter needs no parentheses: x -> x * 2
  • No parameters: () -> System.out.println("hi")
  • Multiple statements need braces and return: (x) -> { int y = x * 2; return y + 1; }

Functional Interfaces

A lambda always implements a functional interface, an interface with exactly one abstract method. java.util.function provides common ones so you rarely need to write your own.

import java.util.function.*;

public class Main {
    public static void main(String[] args) {
        Predicate<Integer> isEven = n -> n % 2 == 0;
        Function<String, Integer> length = s -> s.length();
        Consumer<String> shout = s -> System.out.println(s.toUpperCase() + "!");
        Supplier<Double> random = () -> 4.0; // pretend random
        BinaryOperator<Integer> multiply = (a, b) -> a * b;

        System.out.println(isEven.test(10));
        System.out.println(length.apply("lambda"));
        shout.accept("hello");
        System.out.println(random.get());
        System.out.println(multiply.apply(6, 7));
    }
}
true
6
HELLO!
4.0
42

Lambdas with Collections

Many collection methods accept lambdas, which replaces whole loops with one readable line.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> cities = new ArrayList<>(List.of("Karachi", "Oslo", "Dubai", "Lima"));
        cities.sort((a, b) -> a.length() - b.length());
        System.out.println(cities);
        cities.removeIf(c -> c.startsWith("L"));
        cities.forEach(c -> System.out.println("City: " + c));

        Map<String, Integer> scores = new TreeMap<>(Map.of("Ali", 80, "Zoya", 92));
        scores.forEach((name, score) -> System.out.println(name + " scored " + score));
    }
}
[Oslo, Lima, Dubai, Karachi]
City: Oslo
City: Dubai
City: Karachi
Ali scored 80
Zoya scored 92

List.sort is stable, so Oslo and Lima (both four letters) keep their original order.

Method References

When a lambda just calls an existing method, a method reference using :: is even shorter.

import java.util.List;
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        List<String> words = List.of("alpha", "beta");
        words.forEach(System.out::println);              // s -> System.out.println(s)
        Function<String, Integer> parse = Integer::parseInt; // s -> Integer.parseInt(s)
        Function<String, String> upper = String::toUpperCase;
        System.out.println(parse.apply("21") * 2);
        System.out.println(upper.andThen(s -> s + "?").apply("why"));
    }
}
alpha
beta
42
WHY?

Variable Capture

A lambda can use local variables from the surrounding method, but only if they are effectively final, meaning they are never reassigned after being set.

Frequently asked questions

What is a functional interface in Java?

An interface with exactly one abstract method, such as Runnable, Comparator or Predicate. Any lambda can be used where a functional interface is expected.

What does :: mean in Java?

It creates a method reference, a shorthand for a lambda that only calls one method, like String::length instead of s -> s.length().

Why must variables used in a lambda be effectively final?

The lambda may run later or on another thread, so Java captures a copy of the value. Forbidding reassignment avoids confusing behaviour where the copy and the original differ.