Collectors.mapping în Java

Transformă fiecare element înainte să-l dea altui colector; folosit în groupingBy ca să păstrezi doar un câmp.

Sintaxă
static <T, U, A, R> Collector<T, ?, R> mapping(Function<T, U> f, Collector<U, A, R> downstream)

Ce face Collectors.mapping

mapping(f, colector) face un map(f) chiar în interiorul colectorului. Singur nu aduce mare lucru (poți scrie map înainte de collect), dar în groupingBy sau partitioningBy este singurul mod de a transforma elementele din fiecare grup.

Exemplu tipic: groupingBy(Student::oras, mapping(Student::nume, toList())) dă „oraș → lista numelor”, nu „oraș → lista obiectelor Student”. Asemănător există filtering și flatMapping (Java 9).

Parametri

Parametru Descriere
f Funcția aplicată fiecărui element.
downstream Colectorul care primește valorile transformate.

Ce returnează

Un Collector care produce ce produce colectorul downstream.

Exemple

Exemplul 1: Oraș → numele studenților

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) {}

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

        Map<String, List<String>> nume = studenti.stream()
                .collect(Collectors.groupingBy(Student::oras, TreeMap::new,
                        Collectors.mapping(Student::nume, Collectors.toList())));
        System.out.println(nume);

        Map<String, String> text = studenti.stream()
                .collect(Collectors.groupingBy(Student::oras, TreeMap::new,
                        Collectors.mapping(Student::nume, Collectors.joining(" și "))));
        System.out.println(text);
    }
}

Rezultat

{Cluj=[Radu, Elena], Iași=[Ana, Ioana]}
{Cluj=Radu și Elena, Iași=Ana și Ioana}

Exemplul 2: mapping împreună cu filtering

Pentru fiecare grupă păstrăm doar numele celor cu nota peste 8. Grupa 102 rămâne cu o listă goală, dar apare în rezultat.

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

public class Main {
    record Student(String nume, int grupa, int nota) {}

    public static void main(String[] args) {
        List<Student> studenti = List.of(
                new Student("Ana", 101, 10), new Student("Radu", 101, 6),
                new Student("Ioana", 102, 7), new Student("Dan", 103, 9));

        Map<Integer, List<String>> buni = studenti.stream()
                .collect(Collectors.groupingBy(Student::grupa, TreeMap::new,
                        Collectors.filtering(s -> s.nota() > 8,
                                Collectors.mapping(Student::nume, Collectors.toList()))));
        System.out.println(buni);
    }
}

Rezultat

{101=[Ana], 102=[], 103=[Dan]}

Greșeli frecvente

  • Pui map(Student::nume) înainte de groupingBy(Student::oras): după map nu mai ai orașul. Transformarea trebuie făcută în grup, cu mapping.
  • Uiți al doilea argument. mapping cere mereu colectorul care primește valorile (de exemplu toList()).

Comenzi înrudite

  • Collectors.groupingBy: Împarte elementele în grupuri după o cheie (oraș, grupă, prima literă) și dă un Map cheie → listă sau cheie → rezultat.
  • Stream.map: Transformă fiecare element al stream-ului în altă valoare, eventual de alt tip.
  • Collectors.partitioningBy: Împarte elementele în două grupuri, după o condiție: cele care o îndeplinesc (true) și celelalte (false).
  • Collectors.joining: Unește textele din stream într-un singur String, cu un separator și, opțional, un început și un sfârșit.