π¦
Collections & Generics
Collections & Generics Β· Prerequisite: previous lecture
14. Stream API Introduction
The Stream API (JDK 8+) lets you express collection operations **declaratively**. This lecture covers `filter` / `map` / `reduce`, intermediate vs terminal operations, and `Collectors`.
JavaStreamfiltermapreduceCollectors
Duration
β± ~1.5-2 hours
Level
π Intermediate
Prerequisite
π― Previous lecture or equivalent knowledge
OUTCOME
The Stream API (JDK 8+) lets you express collection operations **declaratively**. This lecture covers `filter` / `map` / `reduce`, intermediate vs terminal operations, and `Collectors`.
What you'll learn
- 1Distinguish intermediate from terminal operations
- 2Combine `filter` / `map` / `sorted` / `reduce`
- 3Convert results with `Collectors.toList`, `groupingBy`
- 4Understand lazy evaluation
Overview
The Stream API (JDK 8+) lets you express collection operations **declaratively**. This lecture covers `filter` / `map` / `reduce`, intermediate vs terminal operations, and `Collectors`.
Core Concepts
1) Creating a stream
java
import java.util.List;
import java.util.stream.Stream;
List.of(1, 2, 3).stream(); // from a collection
Stream.of("a", "b", "c"); // from values
java.util.stream.IntStream.range(0, 5); // primitive int stream2) Intermediate vs terminal
- **Intermediate**: `filter` / `map` / `sorted` / `distinct` β return another `Stream`, lazy
- **Terminal**: `forEach` / `count` / `collect` / `reduce` β trigger evaluation
3) `filter` / `map` / `collect`
java
import java.util.List;
import java.util.stream.Collectors;
List<String> result = List.of(1, 2, 3, 4, 5).stream()
.filter(n -> n % 2 == 0)
.map(n -> "#" + n)
.collect(Collectors.toList());
System.out.println(result); // [#2, #4]4) `reduce`
java
int sum = List.of(1, 2, 3, 4).stream()
.reduce(0, Integer::sum); // 105) `Collectors.groupingBy`
java
Map<Integer, List<String>> byLen = List.of("a", "bb", "cc", "ddd").stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(byLen); // {1=[a], 2=[bb, cc], 3=[ddd]}Examples
Example 1 β `BasicStream.java`
java
import java.util.List;
public class BasicStream {
public static void main(String[] args) {
var nums = List.of(1, 2, 3, 4, 5);
long even = nums.stream().filter(n -> n % 2 == 0).count();
int sum = nums.stream().mapToInt(Integer::intValue).sum();
System.out.println("even=" + even);
System.out.println("sum=" + sum);
}
}**Output**
text
even=2
sum=15Example 2 β `FilterMapCollect.java`
java
import java.util.List;
import java.util.stream.Collectors;
public class FilterMapCollect {
public static void main(String[] args) {
var result = List.of("apple", "banana", "cherry", "fig").stream()
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
System.out.println(result);
}
}**Output**
text
[APPLE, BANANA, CHERRY]Example 3 β `Reduce.java`
java
import java.util.List;
public class Reduce {
public static void main(String[] args) {
int sum = List.of(1, 2, 3, 4, 5).stream()
.reduce(0, Integer::sum);
int max = List.of(3, 1, 4, 1, 5, 9, 2).stream()
.reduce(Integer.MIN_VALUE, Integer::max);
System.out.println("sum=" + sum);
System.out.println("max=" + max);
}
}**Output**
text
sum=15
max=9Example 4 β `Grouping.java`
java
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Grouping {
record Person(String name, int age) {}
public static void main(String[] args) {
var people = List.of(
new Person("Jisoo", 21),
new Person("Minsu", 25),
new Person("Hana", 21),
new Person("Tom", 30)
);
Map<Integer, List<String>> byAge = people.stream()
.collect(Collectors.groupingBy(
Person::age,
Collectors.mapping(Person::name, Collectors.toList())));
byAge.forEach((k, v) -> System.out.println(k + " -> " + v));
}
}**Output**
text
21 -> [Jisoo, Hana]
25 -> [Minsu]
30 -> [Tom]Common Mistakes
- Reusing a stream after a terminal operation β `IllegalStateException`
- Forgetting that intermediate operations are lazy β nothing runs without a terminal
- Mutating an external variable inside `map` / `filter` (use stateless lambdas)
- Using `forEach` with side effects when you really want `collect`
- Reaching for `parallelStream` blindly β overhead can exceed any gain
Summary
- Streams compose **intermediate** ops on top of each other, then run on a **terminal**
- `filter` / `map` / `collect` covers most needs
- `Collectors` (especially `groupingBy`) is incredibly flexible
Practice
# Practice - 14. Stream API
## Exercise 1 β Average of even numbers
- File: `Homework01.java`
- Key concepts: `filter`, `mapToInt`, `average`
Requirements
- From `{1..10}` compute the average of the even numbers.
Expected output
text
avg=6.0## Exercise 2 β Group people by age
- File: `Homework02.java`
- Key concepts: `groupingBy`
Requirements
- Given 4 `Person(name, age)` records, group by age and print.
Expected output
text
20 -> [A]
21 -> [B, C]
30 -> [D]## Solutions After trying it yourself, compare with [`answer/`](./answer/).
Solution code (homework/answer/)
answer/Homework01.java
java
import java.util.stream.IntStream;
/** Average of even numbers. */
public class Homework01 {
public static void main(String[] args) {
double avg = IntStream.rangeClosed(1, 10)
.filter(n -> n % 2 == 0)
.average()
.orElse(0);
System.out.println("avg=" + avg);
}
}
answer/Homework02.java
java
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
/** Group people by age. */
public class Homework02 {
record Person(String name, int age) {}
public static void main(String[] args) {
var people = List.of(
new Person("A", 20),
new Person("B", 21),
new Person("C", 21),
new Person("D", 30));
Map<Integer, List<String>> byAge = people.stream()
.collect(Collectors.groupingBy(
Person::age,
TreeMap::new,
Collectors.mapping(Person::name, Collectors.toList())));
byAge.forEach((k, v) -> System.out.println(k + " -> " + v));
}
}
Try It Yourself
bash
cd 03_collections/14_stream/src
javac FilterMapCollect.java
java FilterMapCollectNext Lecture
[15_Exception](../../04_μμΈ_μ μΆλ ₯/15_μμΈ_μ²λ¦¬/) β exception handling.
Example code / lecture materials
All lecture materials and example code are openly available on GitHub.
View on GitHub β