Java Lambda Expressions

A lambda expression is a short block of code you can pass around like a value. Introduced in Java 8, lambdas let you write behaviour inline instead of creating a whole class, which makes working with collections and functional interfaces much cleaner.

Before lambdas, if you wanted to hand a piece of behaviour to a method, you had to write a full anonymous class, which was very wordy. A lambda expression captures just the important part: the parameters and the code to run. Think of it as a nameless method you can store in a variable or pass as an argument.

Lambda syntax

The basic shape is parameters, then an arrow ->, then the body. If the body is a single expression, its result is returned automatically and you do not need braces or the return keyword. If you need several statements, wrap them in braces and return explicitly.

Different lambda forms

// No parameters
Runnable greet = () -> System.out.println("Hello!");

// One parameter, single expression (parentheses optional)
// takes a number, returns its square
java.util.function.Function<Integer, Integer> square = n -> n * n;

// Two parameters
java.util.function.BinaryOperator<Integer> add = (a, b) -> a + b;

// Multiple statements need braces and return
java.util.function.Function<Integer, String> describe = n -> {
  if (n > 0) return "positive";
  else return "not positive";
};

A lambda only works where Java expects a functional interface, which is an interface with exactly one abstract method. The lambda becomes the implementation of that single method. Java's java.util.function package provides many ready-made ones like Function, Consumer, Predicate, and Supplier.

Functional interfaceTakesReturnsTypical use
Consumer<T>One valueNothingforEach, printing
Function<T,R>One valueA resultTransforming values
Predicate<T>One valuebooleanFiltering, testing
Supplier<T>NothingA valueLazily producing a value

Lambdas with collections

The most common place beginners meet lambdas is looping over a collection with forEach, or filtering with streams. The lambda describes what to do with each element, and the collection handles the looping for you.

Using lambdas on an ArrayList

import java.util.ArrayList;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<String> names = new ArrayList<>(List.of("Ann", "Bob", "Amy", "Sam"));

    // forEach with a Consumer lambda
    names.forEach(name -> System.out.println("Hi " + name));

    // filter with a Predicate lambda, keep names starting with A
    names.stream()
         .filter(name -> name.startsWith("A"))
         .forEach(System.out::println); // Ann, Amy
  }
}
Note: The System.out::println part is a method reference, a shorthand for the lambda x -> System.out.println(x). When a lambda simply passes its argument to an existing method, a method reference reads more clearly.
Note: A lambda can use variables from the surrounding code, but those variables must be effectively final, meaning you do not reassign them after the lambda is created. If you try to change such a variable, the compiler will complain.
  • A lambda is a compact, nameless function written as parameters -> body.
  • Lambdas only work where a functional interface (one abstract method) is expected.
  • Single-expression bodies return automatically; multi-line bodies need braces and return.
  • They shine with collection methods like forEach, filter, and map.

Exercise: Java Lambda

What kind of interface can a lambda expression implement?