filter, map, and flatMap

Author      Ter-Petrosyan Hakob

Streams let you transform data easily. Transformation means creating a new stream whose elements are based on another stream.

filter — Keep only what you want

The filter method keeps elements that match a condition. The condition is a Predicate<T>, which is a function returning true or false.

List<String> words = List.of("apple", "banana", "strawberry", "kiwi");

// Keep only long words (length > 5)
Stream<String> longWords = words.stream()
    .filter(w -> w.length() > 5);

longWords.forEach(System.out::println);

map — Transform each element

Use map when you want to change each element in a stream. The function you provide returns a new value for each element.

List<String> words = List.of("Apple", "Banana", "Cherry");

// Convert all words to lowercase
Stream<String> lowercaseWords = words.stream()
    .map(String::toLowerCase);

lowercaseWords.forEach(System.out::println);

Here, we used map with a method reference. You can also use a lambda to pick part of a string:

Stream<Character> firstLetters = words.stream()
    .map(w -> w.charAt(0));

firstLetters.forEach(System.out::println);

flatMap — Flatten nested streams

Sometimes a function returns a stream for each element. Using map here gives you a stream of streams, but often you want one flat stream. That’s what flatMap does.

Example: split words into letters:

List<String> words = List.of("cat", "dog");

Stream<String> letters = words.stream()
    .flatMap(w -> Stream.of(w.split("")));

letters.forEach(System.out::println);

Here, flatMap “flattens” the small streams into one big stream.

Using mapMulti — Efficient alternative

If creating many small streams is slow, mapMulti can help. It directly passes results to a collector instead of making new streams.

Example: get each character in a word:

List<String> words = List.of("hi", "ok");

Stream<String> letters = words.stream()
    .mapMulti((word, collector) -> {
        for (char c : word.toCharArray()) {
            collector.accept(String.valueOf(c));
        }
    });

letters.forEach(System.out::println);