CodeGym /Cours /JAVA 25 SELF /Set : HashSet et TreeSet, unicité des éléments

Set : HashSet et TreeSet, unicité des éléments

JAVA 25 SELF
Niveau 26, Leçon 3
Disponible

1. Introduction

Commençons par un exemple de la vie courante. Imaginez que vous organisez une fête et dressez une liste d’invités. Vous envoyez les invitations, puis vous découvrez que la même personne figure dans la liste deux fois (voire trois — eh bien, elle adore les soirées !). Si vous utilisez une liste classique (List), de tels doublons peuvent facilement apparaître. Mais si vous aviez une collection qui ne permettait pas d’ajouter deux fois le même invité — la vie serait plus simple.

C’est là qu’entre en jeu la collection Set — un ensemble.

Set est une collection qui ne stocke que des éléments uniques. Si vous essayez d’ajouter un élément déjà existant, il ne sera tout simplement pas ajouté (et personne ne s’en offusquera).

Interface Set : propriétés essentielles

En Java, Set est une interface qui définit le comportement d’une collection sans doublons. Elle hérite de l’interface Collection, ce qui signifie qu’elle prend en charge des opérations telles que l’ajout (add), la suppression (remove), la vérification de présence (contains) et l’itération.

Caractéristiques clés :

  • Un Set ne peut pas contenir deux éléments identiques.
  • Les éléments peuvent être stockés dans un ordre arbitraire — cela dépend de l’implémentation.
  • Pas d’indices : on ne peut pas accéder à un élément par son numéro, comme dans une liste.

Syntaxe de déclaration

Set<String> guests = new HashSet<>();

2. HashSet : rapide, simple, sans ordre

HashSet est l’implémentation la plus populaire de l’interface Set. Elle est basée sur une table de hachage (comme HashMap, mais sans paire « clé-valeur », seulement avec des valeurs uniques). Son principal atout — la rapidité des opérations d’ajout, de suppression et de recherche.

Comment fonctionne HashSet ?

Imaginez une boîte dans laquelle vous rangez des objets. Pour savoir rapidement s’il y a déjà quelque chose de similaire, chaque objet reçoit son « numéro » — un code de hachage. Lorsque vous ajoutez un élément dans un HashSet, ce code de hachage est d’abord calculé. Si ce hash n’est pas encore présent, l’élément est tranquillement ajouté à la collection. S’il existe déjà, une vérification d’égalité via equals() est effectuée en plus. Et seulement si les objets sont effectivement égaux, le nouvel élément n’est pas ajouté.

Autrement dit, HashSet garantit automatiquement l’unicité : deux objets identiques n’y apparaîtront pas.

Point intéressant : si vous travaillez avec vos propres classes et souhaitez les stocker dans un HashSet, vous devrez redéfinir les méthodes equals() et hashCode(). Sans cela, la collection peut se comporter de manière imprévisible — des objets en apparence identiques pourront être considérés comme différents.

Méthodes principales de HashSet

Set<String> guests = new HashSet<>();

guests.add("John");
guests.add("Mary");
guests.add("Peter");
guests.add("John"); // Doublon ! Ne sera pas ajouté.

System.out.println(guests); // [John, Mary, Peter] — l’ordre peut être quelconque

guests.remove("Peter"); // On supprime un élément
System.out.println(guests.contains("Mary")); // true
System.out.println(guests.size())); // 2

Essayons cela dans le code

Supposons que, dans notre application, nous voulions stocker des noms de tâches uniques afin d’éviter deux tâches portant le même intitulé :

import java.util.HashSet;
import java.util.Set;

public class UniqueTasksDemo {
    public static void main(String[] args) {
        Set<String> tasks = new HashSet<>();
        tasks.add("Faire les devoirs de Java");
        tasks.add("Caresser le chat");
        tasks.add("Faire les devoirs de Java"); // Doublon !

        System.out.println("Liste des tâches :");
        for (String task : tasks) {
            System.out.println("- " + task);
        }
        // La liste ne contiendra que deux tâches, le doublon ne sera pas ajouté
    }
}

3. TreeSet : l’ordre compte !

Parfois, nous avons besoin non seulement de l’unicité, mais aussi d’un ensemble trié d’éléments. Par exemple, on souhaite voir les noms des invités par ordre alphabétique, et non dans un ordre aléatoire. Pour cela, il existe TreeSet.

TreeSet est une implémentation de l’interface Set qui stocke les éléments dans l’ordre trié (croissant). Elle repose sur une structure d’« arbre rouge-noir ».

Exemple d’utilisation de TreeSet

import java.util.Set;
import java.util.TreeSet;

public class SortedGuestsDemo {
    public static void main(String[] args) {
        Set<String> guests = new TreeSet<>();
        guests.add("Victor");
        guests.add("Alex");
        guests.add("Catherine");
        guests.add("Alex"); // Doublon !

        System.out.println("Invités (par ordre alphabétique) :");
        for (String guest : guests) {
            System.out.println("- " + guest);
        }
        // Sortie :
        // - Alex
        // - Victor
        // - Catherine
    }
}

À noter : si vous ajoutez un doublon, il n’apparaîtra pas dans l’ensemble. Tout est comme il se doit !

Quand utiliser TreeSet ?

  • Quand vous avez besoin d’un ensemble trié d’éléments uniques.
  • Quand la recherche rapide est importante, mais que la vitesse d’ajout n’est pas critique (fonctionne un peu plus lentement que HashSet).
  • Si les éléments sont vos propres classes, ils doivent être « comparables » (implémenter l’interface Comparable) ou vous devez fournir votre propre Comparator.

4. Points utiles

HashSet vs TreeSet : que choisir ?

Critère HashSet TreeSet
Ordre de stockage Non garanti Trié par ordre croissant
Vitesse des opérations Plus rapide (O(1)) Plus lent (O(log n))
Exigences sur le type N’importe lequel (il suffit de equals()/hashCode()) Comparable ou Comparator
Scénarios typiques Quand un accès rapide aux éléments uniques est nécessaire Quand un parcours/affichage ordonné est important

Particularités de l’utilisation de Set

  • Pas d’indices. Contrairement à List, Set ne possède pas de méthode get(int index). Si vous avez besoin d’un accès par indice, utilisez List.
  • Pas de doublons. Si vous essayez d’ajouter un élément déjà présent, il ne sera pas ajouté. La méthode add renverra false.
  • Aucun ordre garanti (sauf TreeSet). Dans un HashSet, l’ordre des éléments peut varier à chaque exécution. Si vous avez besoin de conserver l’ordre d’insertion, utilisez LinkedHashSet.
  • Valeurs null.
    • HashSet permet de stocker un seul élément null.
    • TreeSet n’autorise pas l’ajout de null sans Comparator spécial, sinon il y aura une NullPointerException.

5. Cas d’usage typiques pour Set

Suppression des doublons d’une liste

Supposons que nous ayons une liste d’étudiants où certains sont inscrits deux fois. Il faut ne garder que les noms uniques :

import java.util.*;

public class RemoveDuplicatesDemo {
    public static void main(String[] args) {
        List<String> students = Arrays.asList("Anna", "Igor", "Anna", "Mary", "Igor", "Paul");

        Set<String> uniqueStudents = new HashSet<>(students);

        System.out.println("Étudiants uniques : " + uniqueStudents);
        // L’ordre n’est pas garanti !
    }
}

Si vous avez besoin d’un résultat trié, utilisez TreeSet :

Set<String> sortedUniqueStudents = new TreeSet<>(students);
System.out.println("Étudiants uniques (par ordre alphabétique) : " + sortedUniqueStudents);

Vérification de l’unicité (par exemple, de l’identifiant utilisateur)

Set<String> usedLogins = new HashSet<>();
usedLogins.add("student1");
usedLogins.add("java_lover");

String newLogin = "student1";
if (usedLogins.contains(newLogin)) {
    System.out.println("Cet identifiant est déjà pris !");
} else {
    System.out.println("Identifiant disponible !");
}

Itération sur les éléments d’un ensemble

L’itération se fait avec la boucle for-each :

for (String name : uniqueStudents) {
    System.out.println(name);
}

6. Erreurs courantes avec Set

Erreur n° 1 : s’attendre à un ordre déterminé des éléments dans HashSet. Beaucoup de débutants s’étonnent de voir les éléments de l’ensemble s’afficher dans un « ordre étrange ». C’est normal — HashSet ne garantit aucun ordre. Si vous avez besoin de l’ordre d’insertion, utilisez LinkedHashSet ; si vous avez besoin d’un tri, utilisez TreeSet.

Erreur n° 2 : tentative d’accéder à un élément par indice. Parfois, on essaie d’écrire quelque chose comme set.get(0). C’est impossible : Set ne prend pas en charge l’indexation. Besoin d’un accès par indice ? Utilisez List.

Erreur n° 3 : stocker des objets mutables. Si vous stockez des objets dont les champs participant à equals()/hashCode() peuvent changer, après modification de ces champs, l’élément peut se « perdre » pour l’ensemble. Rendez les éléments immuables ou ne modifiez pas les champs d’identification.

Erreur n° 4 : s’attendre à ce que les doublons soient ajoutés. Ajouter plusieurs fois le même élément n’augmentera pas la taille de l’ensemble — les doublons sont ignorés, la méthode add renverra false.

Erreur n° 5 : utilisation de types primitifs. Une écriture comme Set<int> ne compilera pas. Utilisez des classes enveloppes : Set<Integer>, Set<Double>, etc.

1
Mission
JAVA 25 SELF, niveau 26, leçon 3
Bloqué
Liste des participants de l'événement par ordre alphabétique 🤵‍♀️🤵‍♂️
Liste des participants de l'événement par ordre alphabétique 🤵‍♀️🤵‍♂️
1
Mission
JAVA 25 SELF, niveau 26, leçon 3
Bloqué
Optimisation de la liste de courses 🛒✨
Optimisation de la liste de courses 🛒✨
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION