Stream.gather în Java

Aplică o operație intermediară personalizată (un Gatherer): grupuri de câte n, ferestre glisante, totaluri parțiale.

Sintaxă
<R> Stream<R> gather(Gatherer<? super T, ?, R> gatherer)

// gatherere gata făcute în java.util.stream.Gatherers:
windowFixed(int marime), windowSliding(int marime), fold(...), scan(...)

Ce face Stream.gather

gather este operația intermediară „universală”, adăugată în Java 24. Primește un Gatherer, care poate păstra o stare între elemente și poate produce mai multe sau mai puține elemente decât primește. Așa se pot scrie operații care nu existau: împărțirea în grupuri, ferestre, totaluri cumulate.

Clasa Gatherers are câteva gata făcute: windowFixed(n) (liste de câte n elemente), windowSliding(n) (ferestre care se suprapun), scan(initial, f) (rezultatele parțiale ale unui calcul, pas cu pas) și fold(initial, f) (doar rezultatul final, ca un singur element).

Poți scrie și propriul Gatherer cu Gatherer.of(...) sau Gatherer.ofSequential(...), dar pentru începători cele din Gatherers acoperă cazurile obișnuite.

Parametri

Parametru Descriere
gatherer Operația de aplicat, de obicei una din clasa Gatherers.

Ce returnează

Un nou stream cu elementele produse de gatherer.

Exemple

Exemplul 1: Grupuri de câte 3 și ferestre glisante

import java.util.List;
import java.util.stream.Gatherers;

public class Main {
    public static void main(String[] args) {
        List<String> elevi = List.of("Ana", "Bogdan", "Carmen", "Dan", "Elena", "Florin", "Gabi");
        elevi.stream()
                .gather(Gatherers.windowFixed(3))
                .forEach(echipa -> System.out.println("Echipă: " + echipa));

        List<Integer> temperaturi = List.of(10, 12, 15, 11, 9);
        System.out.println(temperaturi.stream().gather(Gatherers.windowSliding(2)).toList());
    }
}

Rezultat

Echipă: [Ana, Bogdan, Carmen]
Echipă: [Dan, Elena, Florin]
Echipă: [Gabi]
[[10, 12], [12, 15], [15, 11], [11, 9]]

Exemplul 2: Sold după fiecare tranzacție, cu scan

scan produce câte un rezultat după fiecare element; fold produce doar totalul final.

import java.util.List;
import java.util.stream.Gatherers;

public class Main {
    public static void main(String[] args) {
        List<Integer> tranzactii = List.of(500, -120, -80, 1000, -300);

        List<Integer> solduri = tranzactii.stream()
                .gather(Gatherers.scan(() -> 0, Integer::sum))
                .toList();
        System.out.println("Sold după fiecare: " + solduri);

        int sold = tranzactii.stream()
                .gather(Gatherers.fold(() -> 0, Integer::sum))
                .findFirst()
                .orElse(0);
        System.out.println("Sold final: " + sold);
    }
}

Rezultat

Sold după fiecare: [500, 380, 300, 1300, 1000]
Sold final: 1000

Exemplul 3: Media mobilă pe 3 zile

import java.util.List;
import java.util.stream.Gatherers;

public class Main {
    public static void main(String[] args) {
        List<Double> vanzari = List.of(120.0, 90.0, 150.0, 200.0, 170.0);
        vanzari.stream()
                .gather(Gatherers.windowSliding(3))
                .map(f -> f.stream().mapToDouble(Double::doubleValue).average().orElse(0))
                .forEach(m -> System.out.printf("%.2f%n", m));
    }
}

Rezultat

120.00
146.67
173.33

Greșeli frecvente

  • Folosești gather pe o versiune Java mai veche de 24. Metoda nu există și codul nu se compilează.
  • Aștepți ca ultima fereastră din windowFixed să fie completă. Dacă elementele nu se împart exact, ultima listă are mai puține elemente.

Comenzi înrudite

  • Stream.reduce: Combină toate elementele într-o singură valoare, aplicând o operație pas cu pas (sumă, produs, maxim, concatenare).
  • Stream.map: Transformă fiecare element al stream-ului în altă valoare, eventual de alt tip.
  • Collectors.groupingBy: Împarte elementele în grupuri după o cheie (oraș, grupă, prima literă) și dă un Map cheie → listă sau cheie → rezultat.
  • Stream.collect: Adună elementele într-un rezultat (listă, set, map, text) folosind un Collector, de obicei din clasa Collectors.