1. Qu’est‑ce qu’un Set ?
En programmation Java, un Set est l’un des types de collection les plus importants. Le mot « Set » vient des mathématiques et, à l’instar d’un ensemble mathématique, il possède la caractéristique clé qu’il ne peut pas contenir d’éléments dupliqués.
Un Set est utilisé lorsque vous ne souhaitez gérer que des valeurs uniques, quel que soit le type de données (nombres, chaînes ou objets).
Quelle est la différence entre Set et List ?
Le Java Collections Framework propose plusieurs structures de données telles que List et Map. Parmi elles, Set et List sont souvent comparés. Leurs principales différences sont les suivantes :
- List : Autorise les valeurs dupliquées et préserve l’ordre des éléments (basé sur l’index).
- Set : N’autorise pas les duplications, et l’ordre des éléments n’est pas garanti (sauf pour certaines implémentations).
En bref, une List est une « collection ordonnée », tandis qu’un Set est une « collection d’éléments uniques ».
Par exemple, si vous devez gérer des identifiants d’utilisateurs sans duplication, un Set est le choix idéal.
Avantages d’utiliser un Set
- Élimination automatique des duplicatas Même lorsqu’on reçoit une grande quantité de données provenant des utilisateurs, le simple fait d’ajouter des éléments à un Set garantit que les duplicatas ne sont stockés qu’une seule fois. Cela supprime le besoin de vérifications manuelles et simplifie l’implémentation.
- Recherche et suppression efficaces Les Sets sont conçus pour effectuer rapidement des vérifications d’existence et des opérations de suppression, bien que les performances varient selon l’implémentation (par ex.
HashSetouTreeSet).
Quand faut‑il utiliser un Set ?
- Lors de la gestion d’informations qui ne doivent pas être dupliquées, comme les adresses e‑mail ou les identifiants d’utilisateurs
- Lorsque l’unicité des données doit être garantie
- Quand vous souhaitez créer efficacement une liste de valeurs uniques à partir d’un grand jeu de données
Comme indiqué ci‑dessus, le Set est le mécanisme standard en Java pour gérer intelligemment les collections qui n’autorisent pas les duplications.
Dans les sections suivantes, nous explorerons en détail les spécifications du Set, les modèles d’utilisation et des exemples de code concrets.
2. Spécifications de base et avantages du Set
En Java, le Set est défini par l’interface java.util.Set. En implémentant cette interface, vous pouvez représenter une collection d’éléments uniques sans duplicatas. Examinons de plus près les spécifications essentielles et les avantages du Set.
Caractéristiques de base de l’interface Set
Un Set possède les caractéristiques suivantes :
- Pas d’éléments dupliqués : si vous essayez d’ajouter un élément déjà présent, il ne sera pas ajouté. Par exemple, même si vous exécutez
set.add("apple")deux fois, seul un « apple » sera stocké. - L’ordre n’est pas garanti (dépend de l’implémentation) : un Set ne garantit pas l’ordre des éléments par défaut. Cependant, certaines implémentations comme
LinkedHashSetetTreeSetgèrent les éléments dans un ordre spécifique. - Gestion des éléments null : la prise en charge de
nulldépend de l’implémentation. Par exemple,HashSetautorise un seul élémentnull, tandis queTreeSetn’en accepte aucun.
Importance de equals et hashCode
Le fait que deux éléments soient considérés comme des duplicatas dans un Set est déterminé par les méthodes equals et hashCode.
Lorsque vous utilisez des classes personnalisées comme éléments d’un Set, ne pas surcharger correctement ces méthodes peut entraîner des duplicatas inattendus ou un comportement de stockage incorrect.
equals: détermine si deux objets sont logiquement égauxhashCode: renvoie une valeur numérique utilisée pour une identification efficace
Avantages d’utiliser un Set
Les Sets offrent plusieurs avantages pratiques :
- Élimination facile des duplicatas : le simple fait d’ajouter des valeurs à un Set garantit que les duplicatas sont automatiquement supprimés, éliminant ainsi le besoin de vérifications manuelles.
- Recherche et suppression efficaces : des implémentations comme
HashSetoffrent des opérations de recherche et de suppression rapides, souvent plus performantes que les Lists. - API simple et intuitive : les méthodes de base comme
add,removeetcontainsrendent les Sets faciles à utiliser.
Implémentation interne et performances
L’une des implémentations de Set les plus courantes, HashSet, utilise en interne un HashMap pour gérer les éléments. Cela permet d’ajouter, de supprimer et de rechercher des éléments avec une complexité moyenne de O(1).
Si un ordre ou un tri est requis, vous pouvez choisir des implémentations telles que LinkedHashSet ou TreeSet selon vos besoins.
3. Principales classes d’implémentation et leurs caractéristiques
Java propose plusieurs implémentations majeures de l’interface Set. Chacune possède des caractéristiques différentes, il est donc important de choisir la bonne selon votre cas d’utilisation.
Ici, nous expliquerons les trois implémentations les plus couramment utilisées : HashSet, LinkedHashSet et TreeSet.
HashSet
HashSet est l’implémentation de Set la plus couramment utilisée.
- Caractéristiques
- Ne préserve pas l’ordre des éléments (l’ordre d’insertion et l’ordre d’itération peuvent différer).
- Utilise en interne un
HashMap, offrant des opérations d’ajout, de recherche et de suppression rapides. - Autorise un élément
null. - Cas d’utilisation typiques
- Idéal lorsque vous souhaitez éliminer les doublons et que l’ordre n’a pas d’importance.
- Exemple de code
Set<String> set = new HashSet<>(); set.add("apple"); set.add("banana"); set.add("apple"); // Duplicate is ignored for (String s : set) { System.out.println(s); // Only "apple" and "banana" are printed }
LinkedHashSet
LinkedHashSet étend la fonctionnalité de HashSet en préservant l’ordre d’insertion.
- Caractéristiques
- Les éléments sont itérés dans l’ordre dans lequel ils ont été insérés.
- Géré en interne à l’aide d’une combinaison d’une table de hachage et d’une liste chaînée.
- Légèrement plus lent que
HashSet, mais utile lorsque l’ordre est important. - Cas d’utilisation typiques
- Idéal lorsque vous souhaitez supprimer les doublons tout en conservant l’ordre d’insertion.
- Exemple de code
Set<String> set = new LinkedHashSet<>(); set.add("apple"); set.add("banana"); set.add("orange"); for (String s : set) { System.out.println(s); // Printed in order: apple, banana, orange }
TreeSet
TreeSet est une implémentation de Set qui trie automatiquement les éléments.
- Caractéristiques
- Utilise en interne un arbre rouge-noir (une structure d’arbre équilibré).
- Les éléments sont automatiquement triés par ordre croissant.
- Un ordre personnalisé est possible en utilisant
ComparableouComparator. - Les valeurs
nullne sont pas autorisées. - Cas d’utilisation typiques
- Utile lorsque vous avez besoin à la fois d’unicité et de tri automatique.
- Exemple de code
Set<Integer> set = new TreeSet<>(); set.add(30); set.add(10); set.add(20); for (Integer n : set) { System.out.println(n); // Printed in order: 10, 20, 30 }
Résumé
- HashSet : Idéal pour des performances élevées lorsque l’ordre n’est pas requis
- LinkedHashSet : À utiliser lorsque l’ordre d’insertion est important
- TreeSet : À utiliser lorsque le tri automatique est requis
Le choix de la bonne implémentation de Set dépend de vos exigences spécifiques. Sélectionnez celle qui convient le mieux et utilisez‑la efficacement.
4. Méthodes courantes et comment les utiliser
L’interface Set fournit diverses méthodes pour les opérations de collection. Vous trouverez ci‑dessous les méthodes les plus couramment utilisées, expliquées avec des exemples.
Méthodes principales
add(E e)Ajoute un élément au Set. Si l’élément existe déjà, il n’est pas ajouté.remove(Object o)Supprime l’élément spécifié du Set. Retourne true si l’opération réussit.contains(Object o)Vérifie si le Set contient l’élément spécifié.size()Retourne le nombre d’éléments dans le Set.clear()Supprime tous les éléments du Set.isEmpty()Vérifie si le Set est vide.iterator()Retourne un Iterator pour parcourir les éléments.toArray()Convertit le Set en tableau.
Exemple d’utilisation de base
Set<String> set = new HashSet<>();
// Add elements
set.add("apple");
set.add("banana");
set.add("apple"); // Duplicate ignored
// Get size
System.out.println(set.size()); // 2
// Check existence
System.out.println(set.contains("banana")); // true
java // Supprimer l’élément set.remove(« banana »); System.out.println(set.contains(« banana »)); // faux
// Effacer tous les éléments set.clear(); System.out.println(set.isEmpty()); // vrai
### Iterating Over a Set
Since Set does not support index-based access (e.g., set.get(0)), use an Iterator or enhanced for-loop.
// Boucle for améliorée
Set
for (String s : set) { System.out.println(s); }
// Utilisation de l’itérateur
Iterator
### Important Notes
* Adding an existing element using `add` does not change the Set.
* Element order depends on the implementation (HashSet: unordered, LinkedHashSet: insertion order, TreeSet: sorted).
## 5. Common Use Cases and Typical Scenarios
Java Sets are widely used in many situations where **duplicate values must be avoided**. Below are some of the most common and practical use cases encountered in real-world development.
### Creating a Unique List (Duplicate Removal)
When you want to **extract only unique values from a large dataset**, Set is extremely useful.
For example, it can automatically remove duplicates from user input or existing collections.
**Example: Creating a Set from a List to Remove Duplicates**
List
System.out.println(set); // [apple, banana, orange]
### Ensuring Input Uniqueness
Sets are ideal for scenarios where **duplicate values must not be registered**, such as user IDs or email addresses.
You can immediately determine whether a value already exists by checking the return value of `add`.
Set
### Storing Custom Classes and Implementing equals/hashCode
When storing custom objects in a Set, proper implementation of **equals** and **hashCode** is essential.
Without them, objects with the same logical content may be treated as different elements.
**Example: Ensuring Uniqueness in a Person Class**
class Person { String name;
Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
// Exemple d’utilisation
Set
### Fast Lookup and Data Filtering
Because Set provides fast lookups via `contains`, it is often used for filtering and comparison tasks.
Converting a List to a Set can significantly improve performance when repeatedly checking for existence.
**Example: Fast Keyword Lookup**
Set
## 6. Performance Considerations and Pitfalls
While Set is a powerful collection for managing unique elements, improper usage can lead to unexpected behavior or performance issues. This section explains key performance characteristics and common pitfalls.
### Performance Differences by Implementation
- HashSet utilise une table de hachage en interne, offrant des performances moyennes O(1) pour les opérations d’ajout, de suppression et de recherche. Les performances peuvent se dégrader si le nombre d’éléments devient extrêmement grand ou si les collisions de hachage sont fréquentes.
- LinkedHashSet performances similaires à HashSet, mais avec une surcharge supplémentaire due au maintien de l’ordre d’insertion. Dans la plupart des cas, la différence est négligeable sauf lors du traitement de très grands ensembles de données.
- TreeSet utilise un arbre rouge‑noir en interne, ce qui donne des performances O(log n) pour les opérations d’ajout, de suppression et de recherche. Plus lent que HashSet, mais fournit un tri automatique.
Utilisation d’objets mutables comme éléments d’un Set
Une prudence supplémentaire est requise lors du stockage d’objets mutables dans un Set.
HashSet et TreeSet s’appuient sur les valeurs hashCode ou compareTo pour gérer les éléments.
Si ces valeurs changent après l’insertion, la recherche et la suppression peuvent échouer.
Exemple : Piège avec des objets mutables
Set<Person> people = new HashSet<>();
Person p = new Person("Taro");
people.add(p);
p.name = "Jiro"; // Modifying after insertion
people.contains(p); // May return false unexpectedly
Pour éviter de tels problèmes, il est fortement recommandé d’utiliser des objets immuables comme éléments d’un Set chaque fois que possible.
Gestion des valeurs null
- HashSet / LinkedHashSet : Autorise un seul élément null
- TreeSet : N’autorise pas null (lance NullPointerException)
Autres notes importantes
- Modification pendant l’itération Modifier un Set pendant son itération peut provoquer une
ConcurrentModificationException. UtilisezIterator.remove()au lieu de modifier directement le Set. - Choisir la bonne implémentation Utilisez
LinkedHashSetouTreeSetlorsque l’ordre est important.HashSetne garantit pas l’ordre.
7. Tableau comparatif (Vue d’ensemble)
Le tableau ci-dessous résume les différences entre les principales implémentations de Set pour une comparaison facile.
| Implementation | No Duplicates | Order Preserved | Sorted | Performance | null Allowed | Typical Use Case |
|---|---|---|---|---|---|---|
| HashSet | Yes | No | No | Fast (O(1)) | One allowed | Duplicate removal, order not required |
| LinkedHashSet | Yes | Yes (Insertion order) | No | Slightly slower than HashSet | One allowed | Duplicate removal with order preservation |
| TreeSet | Yes | No | Yes (Automatic) | O(log n) | Not allowed | Duplicate removal with sorting |
Points clés à retenir
- HashSet : Le choix par défaut lorsque l’ordre n’est pas pertinent et que les performances sont critiques.
- LinkedHashSet : Le meilleur choix lorsque l’ordre d’insertion doit être préservé.
- TreeSet : Idéal lorsque le tri automatique est requis.
8. Questions fréquemment posées (FAQ)
Q1. Les types primitifs (int, char, etc.) peuvent-ils être utilisés dans un Set ?
A1. Non. Utilisez des classes enveloppantes comme Integer ou Character à la place.
Q2. Que se passe-t-il si la même valeur est ajoutée plusieurs fois ?
A2. Seule la première insertion est conservée. La méthode add renvoie false si l’élément existe déjà.
Q3. Quand devrais-je utiliser List vs Set ?
A3. Utilisez List lorsque l’ordre ou les doublons sont importants, et Set lorsque l’unicité est requise.
Q4. Qu’est-ce qui est requis pour stocker des objets personnalisés dans un Set ?
A4. Surcharger correctement equals et hashCode.
Q5. Comment puis-je préserver l’ordre d’insertion ?
A5. Utilisez LinkedHashSet.
Q6. Comment puis-je trier les éléments automatiquement ?
A6. Utilisez TreeSet.
Q7. Un Set peut-il contenir des valeurs null ?
A7. HashSet et LinkedHashSet autorisent un null ; TreeSet n’en autorise pas.
Q8. Comment obtenir la taille d’un Set ?
A8. Utilisez size().
Q9. Comment convertir un Set en List ou en tableau ?
A9.
- En tableau :
toArray() - En List :
new ArrayList<>(set)
Q10. Puis-je supprimer des éléments pendant l’itération ?
A10. Oui, mais uniquement en utilisant Iterator.remove().
9. Conclusion
Cet article a couvert les collections Set de Java, des fondamentaux à l’utilisation avancée. Les points clés incluent :
- Set est conçu pour gérer des collections d’éléments uniques, ce qui le rend idéal pour l’élimination des doublons.
- Les principales implémentations comprennent HashSet (rapide, non ordonné), LinkedHashSet (ordre d’insertion) et TreeSet (trié).
- Les cas d’utilisation courants incluent la suppression de doublons, les vérifications d’unicité, la gestion d’objets personnalisés et les recherches rapides.
- Comprendre les caractéristiques de performance et les pièges tels que les objets mutables et les règles d’itération est essentiel.
- Le tableau comparatif et la FAQ offrent des conseils pratiques pour le développement en conditions réelles.
Maîtriser les collections Set rend la programmation Java plus propre, plus sûre et plus efficace.
Ensuite, envisagez de combiner les Sets avec les Listes ou les Maps pour créer des structures de données et des solutions plus avancées.

### Ensuring Input Uniqueness
Sets are ideal for scenarios where **duplicate values must not be registered**, such as user IDs or email addresses.
You can immediately determine whether a value already exists by checking the return value of `add`.
