Collectors.minBy în Java

Găsește elementul cel mai mic (minBy) sau cel mai mare (maxBy) după un Comparator; util pe grupuri, cu groupingBy.

Sintaxă
static <T> Collector<T, ?, Optional<T>> minBy(Comparator<T> comparator)
static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<T> comparator)

Ce face Collectors.minBy

minBy(comparator) și maxBy(comparator) aleg elementul minim, respectiv maxim, după regula din Comparator, de exemplu Comparator.comparingInt(Student::nota). Rezultatul este un Optional, gol dacă nu există elemente.

Pentru tot stream-ul, stream.min(...) și stream.max(...) sunt mai scurte. minBy/maxBy se folosesc în groupingBy: „cel mai bun student din fiecare grupă”. Dacă vrei valoarea fără Optional, învelește colectorul în collectingAndThen(..., Optional::orElseThrow).

Parametri

Parametru Descriere
comparator Regula de comparare a elementelor.

Ce returnează

Un Collector care produce un Optional<T> cu elementul găsit.

Exemple

Exemplul 1: Cel mai bun student din fiecare grupă

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
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, 9), new Student("Radu", 101, 10),
                new Student("Ioana", 102, 8), new Student("Dan", 102, 6));

        Map<Integer, Optional<Student>> ceiMaiBuni = studenti.stream()
                .collect(Collectors.groupingBy(Student::grupa, TreeMap::new,
                        Collectors.maxBy(Comparator.comparingInt(Student::nota))));
        ceiMaiBuni.forEach((g, s) -> System.out.println(g + ": " + s.map(Student::nume).orElse("-")));
    }
}

Rezultat

101: Radu
102: Ioana

Exemplul 2: Cel mai ieftin produs, fără Optional în rezultat

collectingAndThen aplică o funcție după colectare; aici scoate valoarea din Optional.

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

public class Main {
    record Produs(String nume, String raion, int pret) {}

    public static void main(String[] args) {
        List<Produs> produse = List.of(
                new Produs("mere", "fructe", 6), new Produs("banane", "fructe", 8),
                new Produs("lapte", "lactate", 9), new Produs("iaurt", "lactate", 4));

        Map<String, String> ieftine = produse.stream()
                .collect(Collectors.groupingBy(Produs::raion, TreeMap::new,
                        Collectors.collectingAndThen(
                                Collectors.minBy(Comparator.comparingInt(Produs::pret)),
                                p -> p.map(Produs::nume).orElseThrow())));
        System.out.println(ieftine);

        Optional<Produs> scump = produse.stream().collect(Collectors.maxBy(Comparator.comparingInt(Produs::pret)));
        System.out.println("Cel mai scump: " + scump.orElseThrow().nume());
    }
}

Rezultat

{fructe=mere, lactate=iaurt}
Cel mai scump: lapte

Greșeli frecvente

  • Te aștepți ca la egalitate să primești toate elementele. minBy/maxBy dau unul singur; pentru toți, grupează după notă și ia grupul maxim.
  • Apelezi get() pe Optional fără verificare. În groupingBy grupurile nu sunt goale, dar pe un stream gol Optional este gol.

Comenzi înrudite

  • Stream.min / Stream.max: Găsesc cel mai mic și cel mai mare element după un Comparator; rezultatul este un Optional.
  • Collectors.groupingBy: Împarte elementele în grupuri după o cheie (oraș, grupă, prima literă) și dă un Map cheie → listă sau cheie → rezultat.
  • Collectors.teeing: Trimite fiecare element la doi colectori deodată și unește cele două rezultate cu o funcție, într-o singură parcurgere.
  • IntStream.max: Returnează cel mai mare (max) sau cel mai mic (min) număr din IntStream, ca OptionalInt.