← Back to Java series
🔧
Modern Java
Modern Java · Prerequisite: previous lecture

18. Lambdas and Functional Interfaces

A **lambda** is a concise **anonymous function**. Since JDK 8 it's the core syntax you see everywhere — collections, Stream, Spring. This lecture also covers method references and the standard functional interfaces (`Function` / `Predicate` / `Consumer` / `Supplier`).

Javamodernfunctionallambda
Duration
~1.5-2 hours
Level
📊 Intermediate-Advanced
Prerequisite
🎯 Previous lecture or equivalent knowledge
OUTCOME
A **lambda** is a concise **anonymous function**. Since JDK 8 it's the core syntax you see everywhere — collections, Stream, Spring. This lecture also covers method references and the standard functional interfaces (`Function` / `Predicate` / `Consumer` / `Supplier`).

What you'll learn

  • 1Know the lambda syntax (`(a, b) -> a + b`)
  • 2Know the four kinds of method reference (`Foo::bar`)
  • 3Use the four core functional interfaces in `java.util.function`
  • 4Understand the effectively-final restriction on captured variables

Overview

A **lambda** is a concise **anonymous function**. Since JDK 8 it's the core syntax you see everywhere — collections, Stream, Spring. This lecture also covers method references and the standard functional interfaces (`Function` / `Predicate` / `Consumer` / `Supplier`).

Core Concepts

1) Lambda expressions

java
Runnable r = () -> System.out.println("hi");
Comparator<String> byLen = (a, b) -> a.length() - b.length();

The type is inferred from the target functional interface.

2) Four kinds of method reference

KindExample
Static method`Integer::parseInt`
Instance method (specific object)`System.out::println`
Instance method (class name)`String::toUpperCase`
Constructor`ArrayList::new`

3) Standard functional interfaces

InterfaceAbstract methodMeaning
`Function<T, R>``R apply(T)`T → R transformation
`Predicate<T>``boolean test(T)`T → boolean test
`Consumer<T>``void accept(T)`T → side-effect (print, etc.)
`Supplier<T>``T get()`no input → produce T
`BiFunction<T,U,R>``R apply(T, U)`two inputs → one output

4) Effectively final

java
int x = 10;
Runnable r = () -> System.out.println(x);
// x = 20;   // compile error — x must be effectively final

Captured local variables can't be reassigned after the lambda is created.

Examples

Example 1 — `LambdaBasics.java`

java
import java.util.Arrays;
import java.util.List;

public class LambdaBasics {
    public static void main(String[] args) {
        Runnable r = () -> System.out.println("hello lambda");
        r.run();

        List<String> names = Arrays.asList("cherry", "apple", "banana");
        names.sort((a, b) -> a.compareTo(b));
        System.out.println(names);
    }
}

**Output**

text
hello lambda
[apple, banana, cherry]

Example 2 — `MethodReferences.java`

java
import java.util.List;

public class MethodReferences {
    public static void main(String[] args) {
        var nums = List.of("1", "2", "3");
        nums.stream()
            .map(Integer::parseInt)        // static
            .forEach(System.out::println); // instance on specific object
    }
}

**Output**

text
1
2
3

Example 3 — `FunctionalInterfaces.java`

java
import java.util.function.*;

public class FunctionalInterfaces {
    public static void main(String[] args) {
        Function<Integer, Integer> square = n -> n * n;
        Predicate<Integer> isPos = n -> n > 0;
        Consumer<String> printer = System.out::println;
        Supplier<String> hello = () -> "hello";

        System.out.println(square.apply(5));
        System.out.println(isPos.test(-3));
        printer.accept("via Consumer");
        System.out.println(hello.get());
    }
}

**Output**

text
25
false
via Consumer
hello

Example 4 — `Capture.java`

java
public class Capture {
    public static void main(String[] args) {
        int base = 10;
        Runnable add = () -> System.out.println(base + 5);
        add.run();
        // base = 20;   // would be a compile error
    }
}

**Output**

text
15

Common Mistakes

  1. Reassigning a captured variable after the lambda is defined
  2. Using `this` inside a lambda and expecting it to mean the enclosing class — actually it does (anonymous classes are the exception)
  3. Confusing method references — `String::length` (class) vs `s::length` (specific instance)
  4. Throwing checked exceptions from a lambda assigned to a functional interface that doesn't declare them
  5. Choosing a single-line lambda when a method reference would be clearer

Summary

  • Lambdas are concise implementations of functional interfaces
  • Method references are even more concise when applicable
  • Master `Function` / `Predicate` / `Consumer` / `Supplier`

Practice

# Practice - 18. Lambdas

## Exercise 1 — Sort by string length

  • File: `Homework01.java`
  • Key concepts: lambda, `Comparator`

Requirements

  • Sort `["cherry", "fig", "apple", "banana"]` by length ascending using a lambda.

Expected output

text
[fig, apple, cherry, banana]

## Exercise 2 — Functional pipeline

  • File: `Homework02.java`
  • Key concepts: `Function`, `Predicate`

Requirements

  • Filter even numbers, square them, print the result for `1..6`.

Expected output

text
4
16
36

## Solutions After trying it yourself, compare with [`answer/`](./answer/).

Solution code (homework/answer/)

answer/Homework01.java

java
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/** Sort by length. */
public class Homework01 {
    public static void main(String[] args) {
        List<String> list = new java.util.ArrayList<>(Arrays.asList("cherry", "fig", "apple", "banana"));
        list.sort(Comparator.comparingInt(String::length));
        System.out.println(list);
    }
}

answer/Homework02.java

java
import java.util.stream.IntStream;

/** Filter even, square, print. */
public class Homework02 {
    public static void main(String[] args) {
        IntStream.rangeClosed(1, 6)
            .filter(n -> n % 2 == 0)
            .map(n -> n * n)
            .forEach(System.out::println);
    }
}

Try It Yourself

bash
cd 05_modern/18_lambda/src
javac LambdaBasics.java
java LambdaBasics

Next Lecture

[19_Optional](../19_Optional/) — express the possibility of "no value" with `Optional<T>`.

Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗