Ce face Stream.reduce
reduce(identitate, f) pornește de la identitate și o combină cu fiecare element: rezultat = f(rezultat, element). Pentru sumă, identitatea este 0 și funcția Integer::sum; pentru produs, 1 și (a, b) -> a * b.
Varianta fără identitate returnează un Optional, gol dacă stream-ul nu are elemente. Varianta cu trei argumente permite un rezultat de alt tip decât elementele (de exemplu, suma prețurilor dintr-un stream de produse).
Operația trebuie să fie asociativă ((a+b)+c == a+(b+c)), iar identitatea trebuie să nu schimbe nimic (0 pentru sumă). Altfel, pe stream-uri paralele rezultatul iese greșit.
Parametri
| Parametru | Descriere |
|---|---|
identitate |
Valoarea de pornire și rezultatul pentru un stream gol. |
combina / acumuleaza |
Funcția care unește rezultatul parțial cu următorul element. |
Ce returnează
Valoarea combinată (de tip T sau U) sau un Optional<T> pentru varianta fără identitate.
Exemple
Exemplul 1: Sumă, produs, maxim
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<Integer> numere = List.of(3, 5, 2, 8);
int suma = numere.stream().reduce(0, Integer::sum);
int produs = numere.stream().reduce(1, (a, b) -> a * b);
Optional<Integer> maxim = numere.stream().reduce(Integer::max);
System.out.println("Sumă: " + suma);
System.out.println("Produs: " + produs);
System.out.println("Maxim: " + maxim.orElseThrow());
System.out.println("Gol: " + List.<Integer>of().stream().reduce(Integer::max));
}
}
Rezultat
Sumă: 18
Produs: 240
Maxim: 8
Gol: Optional.empty
Exemplul 2: Rezultat de alt tip decât elementele
Elementele sunt produse, rezultatul este un double. Al treilea argument unește sumele parțiale (folosit în paralel).
import java.util.List;
public class Main {
record Produs(String nume, double pret) {}
public static void main(String[] args) {
List<Produs> cos = List.of(new Produs("Caiet", 12.5), new Produs("Carte", 45.0), new Produs("Pix", 4.5));
double total = cos.stream()
.reduce(0.0, (suma, p) -> suma + p.pret(), Double::sum);
System.out.println("Total: " + total + " lei");
}
}
Rezultat
Total: 62.0 lei
Exemplul 3: Același rezultat în paralel
Adunarea este asociativă și 0 este identitatea, deci suma este aceeași cu sau fără parallel().
import java.util.stream.LongStream;
public class Main {
public static void main(String[] args) {
long secvential = LongStream.rangeClosed(1, 1_000_000).reduce(0, Long::sum);
long paralel = LongStream.rangeClosed(1, 1_000_000).parallel().reduce(0, Long::sum);
System.out.println(secvential);
System.out.println(paralel);
System.out.println("Egale: " + (secvential == paralel));
}
}
Rezultat
500000500000
500000500000
Egale: true
Greșeli frecvente
- Dai o identitate greșită, de exemplu
reduce(10, Integer::sum)pentru „sumă plus 10”. În paralel,10se adaugă o dată pentru fiecare bucată; adaugă 10 dupăreduce. - Folosești
reducecu o operație neasociativă, ca scăderea. Rezultatul diferă în paralel. - Folosești
reducepentru a construi liste sau texte lungi. Este lent; foloseștecollect/Collectors.joining.
Comenzi înrudite
Stream.collect: Adună elementele într-un rezultat (listă, set, map, text) folosind un Collector, de obicei din clasa Collectors.BinaryOperator: O funcție care combină două valori de același tip într-una (T, T → T); folosită de reduce, toMap și Map.merge.IntStream.sum: sum adună numerele din IntStream; average dă media lor ca OptionalDouble (gol dacă nu există numere).Collectors.reducing: Varianta de colector a lui reduce: combină elementele două câte două; util ca downstream în groupingBy.Stream.min / Stream.max: Găsesc cel mai mic și cel mai mare element după un Comparator; rezultatul este un Optional.