Stream.flatMap în Java

Transformă fiecare element într-un stream și lipește toate aceste stream-uri într-unul singur.

Sintaxă
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> f)

Ce face Stream.flatMap

flatMap(f) este util când fiecare element produce mai multe valori (sau niciuna). Funcția f returnează un stream pentru fiecare element, iar flatMap le pune pe toate unul după altul într-un singur stream „plat”.

Exemplul tipic: o listă de liste (List<List<String>>) devine un stream cu toate elementele, cu flatMap(List::stream). La fel, propozițiile se pot împărți în cuvinte cu flatMap(p -> Arrays.stream(p.split(" "))).

Parametri

Parametru Descriere
f Funcția care primește un element și returnează un stream (poate fi gol).

Ce returnează

Un Stream<R> cu elementele tuturor stream-urilor produse, în ordine.

Exemple

Exemplul 1: Din grupe în lista tuturor studenților

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<List<String>> grupe = List.of(
                List.of("Ana", "Bogdan"),
                List.of("Carmen"),
                List.of("Dan", "Elena", "Florin"));

        System.out.println("Cu map:     " + grupe.stream().map(List::stream).count() + " stream-uri");
        List<String> toti = grupe.stream().flatMap(List::stream).toList();
        System.out.println("Cu flatMap: " + toti);
    }
}

Rezultat

Cu map:     3 stream-uri
Cu flatMap: [Ana, Bogdan, Carmen, Dan, Elena, Florin]

Exemplul 2: Cuvintele distincte dintr-un text

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> randuri = List.of(
                "ana are mere",
                "radu are pere",
                "ana are și prune");

        List<String> cuvinte = randuri.stream()
                .flatMap(r -> Arrays.stream(r.split(" ")))
                .distinct()
                .sorted()
                .toList();
        System.out.println(cuvinte);
    }
}

Rezultat

[ana, are, mere, pere, prune, radu, și]

Exemplul 3: Comenzi cu produse

Fiecare comandă are mai multe produse; flatMap le adună pe toate pentru a calcula totalul.

import java.util.List;

public class Main {
    record Produs(String nume, double pret) {}
    record Comanda(String client, List<Produs> produse) {}

    public static void main(String[] args) {
        List<Comanda> comenzi = List.of(
                new Comanda("Ana", List.of(new Produs("Carte", 45), new Produs("Pix", 5))),
                new Comanda("Mihai", List.of(new Produs("Tabletă", 899))),
                new Comanda("Ioana", List.of()));

        double total = comenzi.stream()
                .flatMap(c -> c.produse().stream())
                .mapToDouble(Produs::pret)
                .sum();
        System.out.println("Total vândut: " + total + " lei");
    }
}

Rezultat

Total vândut: 949.0 lei

Greșeli frecvente

  • Funcția din flatMap returnează o listă, nu un stream (flatMap(c -> c.produse())). Nu se compilează; adaugă .stream().
  • Folosești map în loc de flatMap și obții un stream de stream-uri sau de liste, pe care toList() îl afișează ciudat.

Comenzi înrudite

  • Stream.map: Transformă fiecare element al stream-ului în altă valoare, eventual de alt tip.
  • Stream.flatMapToInt: Ca flatMap, dar fiecare element produce un stream de numere primitive, iar rezultatul este un IntStream, LongStream sau DoubleStream.
  • Stream.mapMulti: Pentru fiecare element trimiți zero, una sau mai multe valori mai departe, apelând consumer.accept(…).
  • Stream.concat: Lipește două stream-uri: întâi toate elementele primului, apoi pe ale celui de-al doilea.
  • Stream.of: Creează un stream direct din câteva valori; ofNullable face un stream gol pentru null, iar empty un stream fără elemente.