8 Essential Java Stream APIs to Simplify Collection Processing

This article introduces eight ready‑to‑use Java Stream APIs—including Stream.ofNullable, Stream.iterate, collectingAndThen, dropWhile/takeWhile, IntStream, teeing, concat, and partitioningBy—showing how each can cleanly handle nulls, generate sequences, transform collections, and combine streams with concise code examples.

Programmer DD
Programmer DD
Programmer DD
8 Essential Java Stream APIs to Simplify Collection Processing

1. Quickly filter null values: Stream.ofNullable

The Java 9 method Stream.ofNullable filters out null elements in a collection, helping avoid NullPointerExceptions.

List<String> names = Arrays.asList("Alice", null, "Bob", null, "Charlie");
List<String> nonNullNames = names.stream()
    .flatMap(Stream::ofNullable)
    .collect(Collectors.toList());
System.out.println(nonNullNames);

Output:

[Alice, Bob, Charlie]

2. Stream iteration: Stream.iterate()

Stream.iterate

creates an infinite sequence from a seed and a unary function.

Stream.iterate(0, n -> n + 2)
    .limit(10)
    .forEach(e -> System.out.println(e));

Output: 0 2 4 6 8 10 12 14 16 18

Note: Because Stream.iterate() generates an infinite stream, you should define a termination condition such as limit , findFirst , or findAny to avoid endless loops.

3. Collection transformation: collectingAndThen()

Introduced in Java 8, collectingAndThen applies a finishing transformation to the result of another collector.

List<String> fruits = Arrays.asList("apple", "banana", "orange");
Map<Integer, String> result = fruits.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(fruits::indexOf, String::toUpperCase),
        Collections::unmodifiableMap));
System.out.println(result);

Output:

{0=APPLE, 1=BANANA, 2=ORANGE}

4. Drop and take while: dropWhile() & takeWhile()

Both methods, added in Java 9, process streams sequentially based on a predicate. takeWhile(): returns elements while the predicate holds. dropWhile(): discards elements while the predicate holds.

List<Integer> numbers = List.of(1,2,3,4,5,6,7);
numbers.stream()
    .dropWhile(n -> n < 3)
    .takeWhile(n -> n < 6)
    .forEach(System.out::println);

Output: 3 4 5

5. Integer streams: IntStream

Java 8 introduced IntStream with two common factories: IntStream.range() – excludes the end value. IntStream.rangeClosed() – includes the end value.

IntStream.range(1,5).forEach(System.out::println); // 1 2 3 4
IntStream.rangeClosed(1,5).forEach(System.out::println); // 1 2 3 4 5

6. Apply multiple collectors: teeing()

Java 12 added teeing to combine two collectors on the same stream.

Stream<Integer> nums = Stream.of(1,2,3,4);
Map<String, Integer> collect = nums.collect(Collectors.teeing(
    Collectors.maxBy(Integer::compareTo),
    Collectors.minBy(Integer::compareTo),
    (e1, e2) -> Map.of("min", e1.get(), "max", e2.get())
));
System.out.println(collect);

Output:

{max=4, min=1}

7. Merge streams: Stream.concat()

Stream.concat

joins two streams into one.

Stream<Integer> stream1 = Stream.of(1,2,3);
Stream<Integer> stream2 = Stream.of(4,5,6);
Stream.concat(stream1, stream2).forEach(System.out::println);

Output: 1 2 3 4 5 6

8. Partitioning: Collectors.partitioningBy

partitioningBy

splits a stream into two groups based on a predicate.

Map<Boolean, List<String>> result1 = Stream.of("apple","banana","orange","grape")
    .collect(Collectors.partitioningBy(f -> f.length() > 5));
System.out.println(result1);

Output:

{false=[apple, grape], true=[banana, orange]}
JavaCollectionsStream APIJava 8Java 9Java 12
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.