Why Streams arrived
Understand the collections pain Streams solved, not the API surface - Streams has its own section.
Open this lesson in the learning hubKey points
- Pre-8, every "filter then transform then total" was a loop with a mutable accumulator and an if.
- The intent was buried in the mechanics: you read the loop to work out what it meant.
- Streams let you say what you want; the library decides how to iterate.
- That separation is what made parallel execution a one-word change later.
- For the full API - collectors, gatherers, laziness - see the Streams section; this lesson is only about the shift.
Example
import java.util.*;
import java.util.stream.*;
public class Main {
record Order(String customer, double total, boolean paid) { }
public static void main(String[] args) {
List<Order> orders = List.of(
new Order("ada", 120.0, true),
new Order("bob", 80.0, false),
new Order("ada", 40.0, true),
new Order("cleo", 200.0, true));
// Java 7: intent hidden in mechanics
double oldWay = 0;
for (Order o : orders) {
if (o.paid()) {
oldWay += o.total();
}
}
// Java 8: intent is the code
double newWay = orders.stream()
.filter(Order::paid)
.mapToDouble(Order::total)
.sum();
System.out.println("loop : " + oldWay);
System.out.println("stream : " + newWay);
}
}
Streams did not make loops faster - they made the intent readable, which made parallelism possible.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Java 8 Course course, and every lesson in it is listed on the Java 8 Course contents page.