Why Streams arrived

Java 8 Course · lesson 6 of 16 · 4 min read

Understand the collections pain Streams solved, not the API surface - Streams has its own section.

Open this lesson in the learning hub

Key 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.