Introduction to Streams

What is a Stream

A stream is a pipeline that processes a sequence of elements. You describe what you want (filter, transform, collect), not how to loop. A stream does not store data and does not change its source.

source           intermediate operations (lazy)          terminal operation
┌──────────┐    ┌────────┐   ┌──────┐   ┌────────┐     ┌──────────────┐
│ List     │ ─► │ filter │ ─►│ map  │ ─►│ sorted │ ──► │ toList/sum/  │ ─► result
│ array    │    └────────┘   └──────┘   └────────┘     │ collect/...  │
│ Stream.of│                                           └──────────────┘
└──────────┘    nothing runs until the terminal operation is called

Loop vs Stream

Example

Find the names of students who scored above 75, in upper case, sorted.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Student> students = List.of(
                new Student("Ravi", 82), new Student("Anu", 64),
                new Student("Zoya", 91), new Student("Dev", 77));

        // Imperative loop
        List<String> result1 = new ArrayList<>();
        for (Student s : students) {
            if (s.marks() > 75) result1.add(s.name().toUpperCase());
        }
        Collections.sort(result1);
        System.out.println("Loop:   " + result1);

        // Stream
        List<String> result2 = students.stream()
                .filter(s -> s.marks() > 75)
                .map(s -> s.name().toUpperCase())
                .sorted()
                .toList();
        System.out.println("Stream: " + result2);
    }
}

record Student(String name, int marks) {}

Output

Loop:   [DEV, RAVI, ZOYA]
Stream: [DEV, RAVI, ZOYA]

Key Properties

  • Lazy: intermediate operations run only when a terminal operation asks for elements.
  • Single use: a stream can be consumed once. Calling a second terminal operation throws IllegalStateException.
  • Non-mutating: the source list is not changed.
  • Can be infinite: Stream.iterate / Stream.generate with limit.

Laziness You Can See

Example

Each element goes through the whole pipeline one at a time, and processing stops as soon as findFirst is satisfied.

import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        var first = Stream.of("apple", "banana", "cherry", "date")
                .filter(s -> { System.out.println("filter " + s); return s.length() > 5; })
                .map(s -> { System.out.println("map    " + s); return s.toUpperCase(); })
                .findFirst();
        System.out.println("Result: " + first.get());
    }
}

Output

filter apple
filter banana
map    banana
Result: BANANA

Stream Sources

SourceCode
Collectionlist.stream(), set.stream(), map.entrySet().stream()
ValuesStream.of("a", "b")
ArrayArrays.stream(arr)
Range of intsIntStream.range(0, 5), IntStream.rangeClosed(1, 5)
InfiniteStream.iterate(1, x -> x * 2), Stream.generate(supplier)
Bounded iterate (Java 9)Stream.iterate(1, x -> x < 100, x -> x * 2)
String"text".chars(), text.lines()
FileFiles.lines(path) (close it: try-with-resources)

Creating Streams

Example

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        System.out.println(Stream.of("red", "green", "blue").toList());
        System.out.println(Arrays.stream(new int[]{3, 1, 2}).sum());
        System.out.println(IntStream.rangeClosed(1, 5).boxed().toList());
        System.out.println(Stream.iterate(1, x -> x * 2).limit(8).toList());
        System.out.println(Stream.iterate(1, x -> x < 100, x -> x * 3).toList());
        System.out.println(Stream.generate(() -> "hi").limit(3).collect(Collectors.joining("-")));
        System.out.println("hello".chars().filter(c -> c == 'l').count());
        Map<String, Integer> stock = new TreeMap<>(Map.of("pen", 10, "book", 0, "bag", 4));
        System.out.println(stock.entrySet().stream().filter(e -> e.getValue() > 0).map(Map.Entry::getKey).toList());
    }
}

Output

[red, green, blue]
6
[1, 2, 3, 4, 5]
[1, 2, 4, 8, 16, 32, 64, 128]
[1, 3, 9, 27, 81]
hi-hi-hi
2
[bag, pen]