Collectors în Java

Clasa cu rețete gata făcute pentru collect: liste, mulțimi, map-uri, texte unite, grupări, numărări și medii.

Sintaxă
import java.util.stream.Collectors;

public final class Collectors

Ce face Collectors

Collectors este o clasă cu metode statice care returnează un Collector, adică o „rețetă” prin care stream.collect(...) adună elementele într-un rezultat: toList(), toSet(), toMap(...), joining(", "), groupingBy(...), counting() și altele.

Colectorii se pot combina: groupingBy și partitioningBy primesc un al doilea colector (numit downstream) care spune ce se întâmplă cu fiecare grup, de exemplu counting() sau averagingDouble(...). Așa obții într-o singură linie „numărul de studenți pe oraș” sau „media pe grupă”.

De obicei se scrie import static java.util.stream.Collectors.*; sau se folosește numele complet: Collectors.joining(). Pe paginile de mai jos folosim numele complet, ca să se vadă de unde vine fiecare metodă.

Ce returnează

Metodele clasei returnează obiecte Collector<T, A, R>, date mai departe lui Stream.collect.

Exemple

Exemplul 1: Același stream, colectori diferiți

import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> orase = List.of("Iași", "Cluj", "Iași", "Brașov", "Cluj", "Arad");

        System.out.println(orase.stream().collect(Collectors.toList()));
        Set<String> sortate = orase.stream().collect(Collectors.toCollection(TreeSet::new));
        System.out.println(sortate);
        System.out.println(orase.stream().collect(Collectors.joining(", ")));
        System.out.println(orase.stream().collect(Collectors.counting()));
    }
}

Rezultat

[Iași, Cluj, Iași, Brașov, Cluj, Arad]
[Arad, Brașov, Cluj, Iași]
Iași, Cluj, Iași, Brașov, Cluj, Arad
6

Exemplul 2: Colectori combinați: câți studenți și ce medie are fiecare oraș

groupingBy împarte studenții pe orașe, iar colectorul al doilea calculează ceva pentru fiecare oraș. TreeMap::new ține orașele sortate.

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class Main {
    record Student(String nume, String oras, double medie) {}

    public static void main(String[] args) {
        List<Student> studenti = List.of(
                new Student("Ana", "Iași", 9.50), new Student("Radu", "Cluj", 8.00),
                new Student("Ioana", "Iași", 7.50), new Student("Dan", "Cluj", 9.00),
                new Student("Elena", "Arad", 10.00));

        Map<String, Long> cati = studenti.stream()
                .collect(Collectors.groupingBy(Student::oras, TreeMap::new, Collectors.counting()));
        Map<String, Double> medii = studenti.stream()
                .collect(Collectors.groupingBy(Student::oras, TreeMap::new, Collectors.averagingDouble(Student::medie)));

        System.out.println("Studenți pe oraș: " + cati);
        System.out.println("Media pe oraș: " + medii);
    }
}

Rezultat

Studenți pe oraș: {Arad=1, Cluj=2, Iași=2}
Media pe oraș: {Arad=10.0, Cluj=8.5, Iași=8.5}

Greșeli frecvente

  • Uiți importul java.util.stream.Collectors și primești cannot find symbol.
  • Afișezi un map produs de groupingBy sau toMap și te bazezi pe ordinea cheilor. Este un HashMap fără ordine garantată; cere un TreeMap (vezi groupingBy).
  • Folosești collect(Collectors.toList()) din obișnuință. Din Java 16, stream.toList() este mai scurt (dar lista returnată nu se poate modifica).

Comenzi înrudite

  • Stream.collect: Adună elementele într-un rezultat (listă, set, map, text) folosind un Collector, de obicei din clasa Collectors.
  • Collectors.toList: Adună elementele stream-ului într-o listă (toList), într-o mulțime fără duplicate (toSet) sau într-o listă ce nu se poate modifica.
  • Collectors.groupingBy: Împarte elementele în grupuri după o cheie (oraș, grupă, prima literă) și dă un Map cheie → listă sau cheie → rezultat.
  • Collectors.joining: Unește textele din stream într-un singur String, cu un separator și, opțional, un început și un sfârșit.
  • Collectors.toMap: Construiește un Map din stream: o funcție dă cheia, alta valoarea; o a treia spune ce faci când cheia se repetă.