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`).
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
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
| Kind | Example |
|---|---|
| Static method | `Integer::parseInt` |
| Instance method (specific object) | `System.out::println` |
| Instance method (class name) | `String::toUpperCase` |
| Constructor | `ArrayList::new` |
3) Standard functional interfaces
| Interface | Abstract method | Meaning |
|---|---|---|
| `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
int x = 10;
Runnable r = () -> System.out.println(x);
// x = 20; // compile error — x must be effectively finalCaptured local variables can't be reassigned after the lambda is created.
Examples
Example 1 — `LambdaBasics.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**
hello lambda
[apple, banana, cherry]Example 2 — `MethodReferences.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**
1
2
3Example 3 — `FunctionalInterfaces.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**
25
false
via Consumer
helloExample 4 — `Capture.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**
15Common Mistakes
- Reassigning a captured variable after the lambda is defined
- Using `this` inside a lambda and expecting it to mean the enclosing class — actually it does (anonymous classes are the exception)
- Confusing method references — `String::length` (class) vs `s::length` (specific instance)
- Throwing checked exceptions from a lambda assigned to a functional interface that doesn't declare them
- 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
[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
4
16
36## Solutions After trying it yourself, compare with [`answer/`](./answer/).
Solution code (homework/answer/)
answer/Homework01.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
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
cd 05_modern/18_lambda/src
javac LambdaBasics.java
java LambdaBasicsNext Lecture
[19_Optional](../19_Optional/) — express the possibility of "no value" with `Optional<T>`.
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗