Java Lambdas & Functional Interfaces

A lambda is a short, anonymous function.

Before and after

Java
// anonymous class — Java 7 style
Runnable r = new Runnable() {
    @Override public void run() {
        System.out.println("Running");
    }
};

// lambda — Java 8+
Runnable r2 = () -> System.out.println("Running");

Syntax

Java
() -> System.out.println("hi")              // no parameters
x  -> x * 2                                  // one parameter, parens optional
(x, y) -> x + y                              // two parameters
(x, y) -> {                                  // block body needs return
    int sum = x + y;
    return sum * 2;
}

Functional interfaces

A lambda can be assigned to any interface with exactly one abstract method. The standard ones live in java.util.function:

Interface Signature Use
Predicate<T> T → boolean filtering
Function<T,R> T → R transforming
Consumer<T> T → void side effects
Supplier<T> () → T producing values
BiFunction<T,U,R> (T,U) → R two inputs
Java
Predicate<String> isLong   = s -> s.length() > 5;
Function<String, Integer> len = s -> s.length();
Consumer<String> printer   = s -> System.out.println(s);
Supplier<Double> random    = () -> Math.random();

System.out.println(isLong.test("Kathmandu"));  // true
System.out.println(len.apply("Nepal"));         // 5
printer.accept("hello");
System.out.println(random.get());

Your own functional interface

Java
@FunctionalInterface
interface Calculator {
    int apply(int a, int b);
}

Calculator add = (a, b) -> a + b;
Calculator mul = (a, b) -> a * b;

System.out.println(add.apply(3, 4));  // 7

The @FunctionalInterface annotation makes the compiler verify there is exactly one abstract method.

Method references

When a lambda just calls an existing method, use :::

Java
list.forEach(System.out::println);        // instead of x -> System.out.println(x)
names.stream().map(String::toUpperCase);  // instead of s -> s.toUpperCase()
list.sort(Comparator.comparing(Book::getTitle));
Supplier<List<String>> maker = ArrayList::new;   // constructor reference

Effectively final capture

A lambda may use local variables only if they never change:

Java
int factor = 2;
Function<Integer, Integer> f = x -> x * factor;   // fine
// factor = 3;   ← breaks the lambda above: not effectively final

Fields have no such restriction — only local variables.