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).
();
Six letters.
Discussion
Loading…