iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Streams API

A Stream is a lazy sequence-of-elements pipeline. filter / map / collect over collections, no manual loops. Operations are intermediate (return a Stream) or terminal (consume it).

Filter, map, collect, group

EXAMPLE
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;

record User(String name, int age, String city, double salary) {}

List<User> users = List.of(
    new User("Ada", 32, "Sydney",    120_000),
    new User("Bo",  28, "Sydney",    95_000),
    new User("Cy",  41, "Melbourne", 140_000),
    new User("Di",  22, "Brisbane",  65_000)
);

// 1) Filter + map + collect
List<String> adultsBySalary = users.stream()
    .filter(u -> u.age() >= 30)
    .sorted(Comparator.comparingDouble(User::salary).reversed())
    .map(User::name)
    .toList();           // immutable List (Java 16+)

// 2) Aggregations
double totalPayroll = users.stream().mapToDouble(User::salary).sum();
double avgAge       = users.stream().mapToInt(User::age).average().orElse(0);
int maxSalary       = users.stream().mapToInt(u -> (int) u.salary()).max().orElse(0);

// 3) Group by
Map<String, List<User>> byCity = users.stream()
    .collect(groupingBy(User::city));

// 4) Group + count
Map<String, Long> countByCity = users.stream()
    .collect(groupingBy(User::city, counting()));

// 5) Group + sum salary
Map<String, Double> payrollByCity = users.stream()
    .collect(groupingBy(User::city, summingDouble(User::salary)));

// 6) Partition (boolean predicate)
Map<Boolean, List<User>> seniors = users.stream()
    .collect(partitioningBy(u -> u.age() >= 35));

// 7) Join strings
String names = users.stream()
    .map(User::name)
    .collect(joining(", ", "[", "]"));
// → "[Ada, Bo, Cy, Di]"

// 8) flatMap — flatten nested
List<String> allTags = posts.stream()
    .flatMap(p -> p.tags().stream())
    .distinct()
    .toList();

// 9) Lazy + short-circuit
Optional<User> first = users.stream()
    .filter(u -> u.salary() > 100_000)
    .findFirst();   // stops as soon as it finds one

// 10) Parallel — when CPU-bound + collection is large
long primesUnder1M = IntStream.range(2, 1_000_000)
    .parallel()
    .filter(MyMath::isPrime)
    .count();

// 11) Numeric streams — IntStream / LongStream / DoubleStream
int[] squares = IntStream.rangeClosed(1, 10)
    .map(n -> n * n)
    .toArray();

// 12) Stream.iterate — infinite + limit
List<BigInteger> fibs = Stream.iterate(
        new BigInteger[] { BigInteger.ZERO, BigInteger.ONE },
        p -> new BigInteger[] { p[1], p[0].add(p[1]) }
    )
    .limit(20)
    .map(p -> p[0])
    .toList();

// 13) collect with custom Collector (rare; usually pre-built ones suffice)
String summary = users.stream()
    .collect(teeing(
        counting(),
        summingDouble(User::salary),
        (count, total) -> count + " users, total=" + total
    ));

Why it matters

Streams replace 5 nested loops with one declarative pipeline. groupingBy + partitioningBy are the killer features — they replace dozens of lines of map-of-map juggling.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import java.util.stream.*;
int total = IntStream.rangeClosed(1, 10)
    .filter(n -> n % 2 == 0)
    .sum();
System.out.println(total);  // 30
Try it Yourself »

Exercise

Collect a stream into a list.

List<Integer> evens = nums.stream().filter(n -> n%2==0). ();

Test yourself

Q1. Streams are…
Q2. A terminal operation triggers…
Q3. Collect a stream into a list with…

Discussion

Loading…