Stream.distinct în Java

Elimină duplicatele din stream, păstrând prima apariție a fiecărei valori.

Sintaxă
Stream<T> distinct()

Ce face Stream.distinct

distinct() lasă să treacă doar elementele care nu au mai apărut. Două elemente sunt considerate egale după equals (și hashCode), deci pentru clasele tale aceste metode trebuie să fie scrise corect. Un record le are automat.

Pe un stream ordonat (din listă), se păstrează prima apariție și ordinea inițială. Dacă vrei valorile unice și sortate, adaugă sorted() după distinct().

Ce returnează

Un stream fără duplicate.

Exemple

Exemplul 1: Orașele unice dintr-o listă de comenzi

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> orase = List.of("Iași", "Cluj", "Iași", "Arad", "Cluj", "Iași");
        System.out.println(orase.stream().distinct().toList());
        System.out.println(orase.stream().distinct().sorted().toList());
        System.out.println("Orașe diferite: " + orase.stream().distinct().count());
    }
}

Rezultat

[Iași, Cluj, Arad]
[Arad, Cluj, Iași]
Orașe diferite: 3

Exemplul 2: Duplicatele la record și la clase obișnuite

Un record are equals generat, deci duplicatele dispar. O clasă fără equals compară adresele obiectelor, deci nu elimină nimic.

import java.util.List;

public class Main {
    record Persoana(String nume, int varsta) {}

    static class Client {
        final String nume;
        Client(String nume) { this.nume = nume; }
    }

    public static void main(String[] args) {
        List<Persoana> p = List.of(new Persoana("Ana", 20), new Persoana("Ana", 20), new Persoana("Ana", 21));
        System.out.println("Persoane distincte: " + p.stream().distinct().count());

        List<Client> c = List.of(new Client("Dan"), new Client("Dan"));
        System.out.println("Clienți distincți: " + c.stream().distinct().count());
    }
}

Rezultat

Persoane distincte: 2
Clienți distincți: 2

Greșeli frecvente

  • Folosești distinct() pe obiecte fără equals/hashCode. Fiecare obiect este diferit de celelalte și nu se elimină nimic.
  • Vrei valori unice „fără să conteze literele mari”. distinct() face diferența între Iași și iași; transformă întâi cu map(String::toLowerCase).

Comenzi înrudite

  • Stream.sorted: Sortează elementele stream-ului, în ordinea naturală sau după un Comparator.
  • 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.
  • Stream.count: Returnează numărul de elemente din stream, de tip long.
  • Stream.filter: Păstrează în stream doar elementele care îndeplinesc o condiție.