Dans vos applications Java, vous travaillerez généralement avec divers types d’objets. Et vous voudrez peut-être effectuer des opérations telles que le tri, la recherche et l’itération sur ces objets.
Avant l’introduction du framework Collections dans JDK 1.2, vous auriez utilisé des tableaux et des vecteurs pour stocker et gérer un groupe d’objets. Mais ils avaient leurs propres inconvénients.
Le framework de collections Java vise à surmonter ces problèmes en fournissant des implémentations de haute performance de structures de données courantes. Cela vous permet de vous concentrer sur l’écriture de la logique de l’application au lieu de vous concentrer sur des opérations de bas niveau.
Ensuite, l’introduction des Génériques dans JDK 1.5 a considérablement amélioré le framework de collections Java. Les Génériques vous permettent d’imposer la sécurité des types pour les objets stockés dans une collection, ce qui renforce la robustesse de vos applications. Vous pouvez en lire plus sur les Génériques Java ici.
Dans cet article, je vais vous guider sur la façon d’utiliser le framework de collections Java. Nous discuterons des différents types de collections, tels que les Listes, les Ensembles, les Files d’attente et les Cartes. Je fournirai également une brève explication de leurs caractéristiques clés telles que :
-
Mécanismes internes
-
Gestion des doublons
-
Support des valeurs nulles
-
Ordonnancement
-
Synchronisation
-
Performance
-
Key methods
-
Common implementations
Nous passerons également en revue quelques exemples de code pour une meilleure compréhension, et j’aborderai la classe utilitaire Collections et son utilisation.
Table des matières:
Comprendre le cadre des collections Java
Selon la documentation Java, “Une collection est un objet qui représente un groupe d’objets. Un cadre de collections est une architecture unifiée pour représenter et manipuler des collections.”
En termes simples, le cadre des collections Java vous aide à gérer un groupe d’objets et à effectuer des opérations sur eux de manière efficace et organisée. Il facilite le développement d’applications en offrant différentes méthodes pour manipuler des groupes d’objets. Vous pouvez ajouter, supprimer, rechercher et trier des objets efficacement en utilisant le cadre des collections Java.
Interfaces de collection
En Java, une interface spécifie un contrat qui doit être respecté par toute classe qui l’implémente. Cela signifie que la classe implémentante doit fournir des implémentations concrètes pour toutes les méthodes déclarées dans l’interface.
Dans le cadre du Java Collections Framework, diverses interfaces de collection telles que Set
, List
et Queue
étendent l’interface Collection
et doivent respecter le contrat défini par l’interface Collection
.
Décodage de la hiérarchie du Java Collections Framework
Découvrez ce joli diagramme provenant de cet article qui illustre la hiérarchie des collections Java :
Nous commencerons par le haut et travaillerons vers le bas afin que vous puissiez comprendre ce que ce diagramme montre :
-
À la racine du Java Collections Framework se trouve l’interface
Iterable
, qui vous permet d’itérer sur les éléments d’une collection. -
L’interface
Collection
étend l’interfaceIterable
. Cela signifie qu’elle hérite des propriétés et du comportement de l’interfaceIterable
et ajoute son propre comportement pour ajouter, supprimer et récupérer des éléments. -
Des interfaces spécifiques telles que
List
,Set
etQueue
étendent encore l’interfaceCollection
. Chacune de ces interfaces a d’autres classes qui implémentent leurs méthodes. Par exemple,ArrayList
est une implémentation populaire de l’interfaceList
,HashSet
implémente l’interfaceSet
, et ainsi de suite. -
L’interface
Map
fait partie du framework de collections Java, mais elle n’étend pas l’interfaceCollection
, contrairement aux autres mentionnées ci-dessus. -
Toutes les interfaces et classes de ce framework font partie du package
java.util
.
Remarque : Une source courante de confusion dans le Framework de Collections Java tourne autour de la différence entre Collection
et Collections
. Collection
est une interface dans le framework, tandis que Collections
est une classe utilitaire. La classe Collections
fournit des méthodes statiques qui effectuent des opérations sur les éléments d’une collection.
Interfaces de Collection Java
À présent, vous êtes familier avec les différents types de collections qui constituent la base du framework de collections. Maintenant, nous allons examiner de plus près les interfaces List
, Set
, Queue
et Map
.
Dans cette section, nous discuterons de chacune de ces interfaces tout en explorant leurs mécanismes internes. Nous examinerons comment elles gèrent les éléments en double et si elles prennent en charge l’insertion de valeurs nulles. Nous comprendrons également l’ordonnancement des éléments lors de l’insertion et leur prise en charge pour la synchronisation, qui traite du concept de sécurité des threads. Ensuite, nous passerons en revue quelques méthodes clés de ces interfaces et conclurons en examinant les implémentations courantes et leurs performances pour diverses opérations.
Avant de commencer, parlons brièvement de la Synchronisation et des Performances.
-
La synchronisation contrôle l’accès aux objets partagés par plusieurs threads, garantissant leur intégrité et prévenant les conflits. Cela est crucial pour maintenir la sécurité des threads.
-
Lors du choix d’un type de collection, un facteur important est sa performance lors d’opérations courantes telles que l’insertion, la suppression et la récupération. La performance est généralement exprimée en utilisant la notation Big-O. Vous pouvez en apprendre davantage à ce sujet ici.
Listes
Un Liste
est une collection ordonnée ou séquentielle d’éléments. Il suit un indexage à partir de zéro, permettant l’insertion, la suppression ou l’accès aux éléments en utilisant leur position d’index.
-
Mécanisme interne: Un
Liste
est supporté en interne par un tableau ou une liste chaînée, selon le type d’implémentation. Par exemple, unArrayListe
utilise un tableau, tandis qu’unLinkedList
utilise une liste chaînée en interne. Vous pouvez en savoir plus surLinkedList
ici. UnListe
redimensionne dynamiquement sa taille lors de l’ajout ou de la suppression d’éléments. La récupération basée sur l’index en fait un type de collection très efficace. -
Doublons : Les éléments en double sont autorisés dans une
List
, ce qui signifie qu’il peut y avoir plus d’un élément dans uneList
avec la même valeur. Toute valeur peut être récupérée en fonction de l’index auquel elle est stockée. -
Null : Les valeurs nulles sont également autorisées dans une
List
. Étant donné que les doublons sont permis, vous pouvez également avoir plusieurs éléments nuls. -
Ordre : Une
List
maintient l’ordre d’insertion, ce qui signifie que les éléments sont stockés dans le même ordre dans lequel ils sont ajoutés. Cela est utile lorsque vous souhaitez récupérer les éléments dans l’ordre exact dans lequel ils ont été insérés. -
Synchronisation: Une
Liste
n’est pas synchronisée par défaut, ce qui signifie qu’elle n’a pas de méthode intégrée pour gérer l’accès par plusieurs threads en même temps. -
Méthodes clés: Voici quelques méthodes clés d’une interface
List
:add(E element)
,get(int index)
,set(int index, E element)
,remove(int index)
etsize()
. Voyons comment utiliser ces méthodes avec un programme d’exemple.import java.util.ArrayList; import java.util.List; public class ListExample { public static void main(String[] args) { // Créer une liste List<String> list = new ArrayList<>(); // add(E element) list.add("Pomme"); list.add("Banane"); list.add("Cerise"); // get(int index) String secondElement = list.get(1); // "Banane" // set(int index, E element) list.set(1, "Myrtille"); // remove(int index) list.remove(0); // Supprime "Pomme" // size() int size = list.size(); // 2 // Afficher la liste System.out.println(list); // Résultat: [Myrtille, Cerise] // Afficher la taille de la liste System.out.println(size); // Résultat: 2 } }
-
Implémentations courantes:
ArrayList
,LinkedList
,Vector
,Stack
-
Performance: En général, les opérations d’insertion et de suppression sont rapides à la fois dans les
ArrayList
et lesLinkedList
. Mais l’accès aux éléments peut être lent car vous devez traverser les nœuds.
Operation | ArrayList | LinkedList |
Insertion | Rapide à la fin – O(1) amorti, lent au début ou au milieu – O(n) | Rapide au début ou au milieu – O(1), lent à la fin – O(n) |
Suppression | Rapide à la fin – O(1) amorti, lent au début ou au milieu – O(n) | Rapide – O(1) si la position est connue |
Récupération | Rapide – O(1) pour un accès aléatoire | Lent – O(n) pour un accès aléatoire, car cela implique de traverser |
Ensembles
Un Set
est un type de collection qui ne permet pas les éléments en double et représente le concept d’un ensemble mathématique.
-
Mécanisme interne: Un
Set
est soutenu en interne par unHashMap
. Selon le type d’implémentation, il est supporté par unHashMap
, unLinkedHashMap
ou unTreeMap
. J’ai écrit un article détaillé sur le fonctionnement interne duHashMap
ici. Assurez-vous de le consulter. -
Doublons: Puisqu’un
Set
représente le concept d’un ensemble mathématique, les éléments en double ne sont pas autorisés. Cela garantit que tous les éléments sont uniques, maintenant l’intégrité de la collection. -
Null: Un maximum d’une valeur nulle est autorisé dans un
Set
car les doublons ne sont pas permis. Mais cela ne s’applique pas à l’implémentation deTreeSet
, où les valeurs nulles ne sont pas du tout autorisées. -
Ordering: L’ordonnancement des éléments dans un
Set
dépend du type d’implémentation.-
HashSet
: L’ordre n’est pas garanti, et les éléments peuvent être placés n’importe où. -
LinkedHashSet
: Cette implémentation maintient l’ordre d’insertion, vous pouvez donc récupérer les éléments dans le même ordre où ils ont été insérés. -
TreeSet
: Les éléments sont insérés en fonction de leur ordre naturel. Alternativement, vous pouvez contrôler l’ordre d’insertion en spécifiant un comparateur personnalisé.
-
-
Synchronisation: Un
Set
n’est pas synchronisé, ce qui signifie que vous pourriez rencontrer des problèmes de concurrence, comme des conditions de course, qui peuvent affecter l’intégrité des données si deux threads ou plus tentent d’accéder simultanément à un objetSet
-
Méthodes clés: Voici quelques méthodes clés d’une interface
Set
:add(E élément)
,remove(Object o)
,contains(Object o)
, etsize()
. Voyons comment utiliser ces méthodes avec un programme d’exemple.import java.util.HashSet; import java.util.Set; public class SetExample { public static void main(String[] args) { // Créer un ensemble Set<String> ensemble = new HashSet<>(); // Ajouter des éléments à l'ensemble ensemble.add("Pomme"); ensemble.add("Banane"); ensemble.add("Cerise"); // Retirer un élément de l'ensemble ensemble.remove("Banane"); // Vérifier si l'ensemble contient un élément boolean contientPomme = ensemble.contains("Pomme"); System.out.println("Contient Pomme: " + contientPomme); // Obtenir la taille de l'ensemble int taille = ensemble.size(); System.out.println("Taille de l'ensemble: " + taille); } }
-
Implémentations courantes:
HashSet
,LinkedHashSet
,TreeSet
-
Performance: Les implémentations de
Set
offrent des performances rapides pour les opérations de base, à l’exception d’unTreeSet
, où les performances peuvent être relativement plus lentes car la structure de données interne implique de trier les éléments pendant ces opérations.
Opération | HashSet | LinkedHashSet | TreeSet |
Insertion | Constante – O(1) | Constante – O(1) | Plus lent – O(log n) |
Suppression | Constante – O(1) | Constante – O(1) | Plus lent – O(log n) |
Récupération | Constante – O(1) | Constante – O(1) | Plus lent – O(log n) |
File d’attente
Une Queue
est une collection linéaire d’éléments utilisée pour contenir plusieurs éléments avant le traitement, suivant généralement l’ordre FIFO (premier entré, premier sorti). Cela signifie que les éléments sont ajoutés à une extrémité et supprimés de l’autre, de sorte que le premier élément ajouté à la file d’attente est le premier à être retiré.
-
Mécanisme interne: Le fonctionnement interne d’une
Queue
peut différer en fonction de sa mise en œuvre spécifique.-
LinkedList
– utilise une liste doublement chaînée pour stocker des éléments, ce qui signifie que vous pouvez parcourir à la fois vers l’avant et vers l’arrière, permettant des opérations flexibles. -
PriorityQueue
– est soutenu en interne par un tas binaire, ce qui est très efficace pour les opérations de récupération. -
ArrayDeque
– est implémenté en utilisant un tableau qui se développe ou se rétrécit lorsque des éléments sont ajoutés ou supprimés. Ici, les éléments peuvent être ajoutés ou supprimés des deux extrémités de la file d’attente.
-
-
Doublons: Dans une
Queue
, des éléments en double sont autorisés, permettant l’insertion de plusieurs instances de la même valeur -
Null: Vous ne pouvez pas insérer de valeur nulle dans une
Queue
car, par conception, certaines méthodes d’uneQueue
retournent null pour indiquer qu’elle est vide. Pour éviter toute confusion, les valeurs nulles ne sont pas autorisées. -
Tri: Les éléments sont insérés en fonction de leur ordre naturel. Sinon, vous pouvez contrôler l’ordre d’insertion en spécifiant un comparateur personnalisé.
-
Synchronisation: Une
Queue
n’est pas synchronisée par défaut. Cependant, vous pouvez utiliser une implémentation deConcurrentLinkedQueue
ou deBlockingQueue
pour assurer la sécurité des threads. -
Méthodes clés: Voici quelques méthodes clés d’une interface
Queue
:add(E element)
,offer(E element)
,poll()
, etpeek()
. Voyons comment utiliser ces méthodes avec un programme d’exemple.import java.util.LinkedList; import java.util.Queue; public class QueueExample { public static void main(String[] args) { // Créer une file d'attente en utilisant LinkedList Queue<String> queue = new LinkedList<>(); // Utiliser la méthode add pour insérer des éléments, lève une exception si l'insertion échoue queue.add("Élément1"); queue.add("Élément2"); queue.add("Élément3"); // Utiliser la méthode offer pour insérer des éléments, renvoie false si l'insertion échoue queue.offer("Élément4"); // Afficher la file d'attente System.out.println("File d'attente: " + queue); // Jeter un œil sur le premier élément (ne le supprime pas) String premierElement = queue.peek(); System.out.println("Jeter un œil : " + premierElement); // affiche "Élément1" // Récupérer le premier élément (le retire) String elementRécupéré = queue.poll(); System.out.println("Récupérer : " + elementRécupéré); // affiche "Élément1" // Afficher la file d'attente après récupération System.out.println("File d'attente après récupération : " + queue); } }
-
Implémentations courantes:
LinkedList
,PriorityQueue
,ArrayDeque
-
Performance: Des implémentations comme
LinkedList
etArrayDeque
sont généralement rapides pour ajouter et supprimer des éléments. LaPriorityQueue
est un peu plus lente car elle insère les éléments en fonction de l’ordre de priorité défini.
Opération | LinkedList | PriorityQueue | ArrayDeque |
Insertion | Rapide au début ou au milieu – O(1), lent à la fin – O(n) | Plus lent – O(log n) | Rapide – O(1), Lent – O(n), si cela implique le redimensionnement du tableau interne |
Suppression | Rapide – O(1) si la position est connue | Plus lent – O(log n) | Rapide – O(1), Lent – O(n), si cela implique le redimensionnement du tableau interne |
Récupération | Lent – O(n) pour un accès aléatoire, car cela implique une traversée | Rapide – O(1) | Rapide – O(1) |
Cartes
Une Map
représente une collection de paires clé-valeur, chaque clé étant associée à une seule valeur. Bien que Map
fasse partie du framework Java Collection, elle n’étend pas l’interface java.util.Collection
.
-
Mécanisme interne: Une
Map
fonctionne en interne en utilisant uneHashTable
basée sur le concept de hachage. J’ai écrit un article détaillé sur ce sujet, alors lisez-le pour une compréhension plus approfondie. -
Doublons: Une
Map
stocke les données sous forme de paires clé-valeur. Ici, chaque clé est unique, donc les clés en double ne sont pas autorisées. Mais les valeurs en double sont permises. -
Nullité: Comme les clés en double ne sont pas autorisées, une
Map
ne peut avoir qu’une seule clé nulle. Comme les valeurs en double sont permises, elle peut avoir plusieurs valeurs nulles. Dans l’implémentation deTreeMap
, les clés ne peuvent pas être nulles car elle trie les éléments en fonction des clés. Cependant, les valeurs nulles sont autorisées. -
Tri: L’ordre d’insertion d’une
Map
varie en fonction de l’implémentation:-
HashMap
– l’ordre d’insertion n’est pas garanti car il est déterminé en fonction du concept de hachage. -
LinkedHashMap
– l’ordre d’insertion est préservé et vous pouvez récupérer les éléments dans le même ordre où ils ont été ajoutés à la collection. -
TreeMap
– Les éléments sont insérés en fonction de leur ordre naturel. Alternativement, vous pouvez contrôler l’ordre d’insertion en spécifiant un comparateur personnalisé.
-
-
Synchronisation : Une
Map
n’est pas synchronisée par défaut. Mais vous pouvez utiliser les implémentationsCollections.synchronizedMap()
ouConcurrentHashMap
pour assurer la sécurité des threads. -
Méthodes clés: Voici quelques méthodes clés d’une interface
Map
:put(K key, V value)
,get(Object key)
,remove(Object key)
,containsKey(Object key)
etkeySet()
. Voyons comment utiliser ces méthodes avec un programme d’exemple.import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapMethodsExample { public static void main(String[] args) { // Créer une nouvelle HashMap Map<String, Integer> map = new HashMap<>(); // put(K key, V value) - Insère des paires clé-valeur dans la map map.put("Pomme", 1); map.put(Banane", 2); map.put(Orange", 3); // get(Object key) - Renvoie la valeur associée à la clé Integer value = map.get("Banane"); System.out.println("Valeur pour 'Banane': " + value); // remove(Object key) - Supprime la paire clé-valeur pour la clé spécifiée map.remove("Orange"); // containsKey(Object key) - Vérifie si la map contient la clé spécifiée boolean hasApple = map.containsKey("Pomme"); System.out.println("Contient 'Pomme': " + hasApple); // keySet() - Renvoie une vue ensemble des clés contenues dans la map Set<String> keys = map.keySet(); System.out.println("Clés dans la map: " + keys); } }
-
Implémentations courantes:
HashMap
,LinkedHashMap
,TreeMap
,Hashtable
,ConcurrentHashMap
-
Performance: L’implémentation de
HashMap
est largement utilisée principalement en raison de ses caractéristiques de performance efficaces telles que décrites dans le tableau ci-dessous.
Opération | HashMap | LinkedHashMap | TreeMap |
Insertion | Rapide – O(1) | Rapide – O(1) | Plus lent – O(log n) |
Suppression | Rapide – O(1) | Rapide – O(1) | Plus lent – O(log n) |
Récupération | Rapide – O(1) | Rapide – O(1) | Plus lent – O(log n) |
Classe utilitaire Collections
Comme souligné au début de cet article, la classe utilitaire Collections
possède plusieurs méthodes statiques utiles qui vous permettent d’effectuer des opérations couramment utilisées sur les éléments d’une collection. Ces méthodes vous aident à réduire le code standard dans votre application et vous permettent de vous concentrer sur la logique métier.
Voici quelques caractéristiques clés et méthodes, ainsi que ce qu’elles font, énumérées brièvement :
-
Triage :
Collections.sort(List<T>)
– cette méthode est utilisée pour trier les éléments d’une liste par ordre croissant. -
Recherche :
Collections.binarySearch(List<T>, key)
– cette méthode est utilisée pour rechercher un élément spécifique dans une liste triée et retourner son index. -
Ordre inverse :
Collections.reverse(List<T>)
– cette méthode est utilisée pour inverser l’ordre des éléments dans une liste. -
Opérations Min/Max :
Collections.min(Collection<T>)
etCollections.max(Collection<T>)
– ces méthodes sont utilisées pour trouver les éléments minimum et maximum dans une collection, respectivement. -
Synchronisation :
Collections.synchronizedList(List<T>)
– cette méthode est utilisée pour rendre une liste thread-safe en la synchronisant. -
Collections non modifiables:
Collections.unmodifiableList(List<T>)
– cette méthode est utilisée pour créer une vue en lecture seule d’une liste, empêchant les modifications.
Voici un programme Java d’exemple qui démontre diverses fonctionnalités de la classe utilitaire Collections
:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(3);
numbers.add(8);
numbers.add(1);
// Tri
Collections.sort(numbers);
System.out.println("Sorted List: " + numbers);
// Recherche
int index = Collections.binarySearch(numbers, 3);
System.out.println("Index of 3: " + index);
// Ordre inverse
Collections.reverse(numbers);
System.out.println("Reversed List: " + numbers);
// Opérations Min/Max
int min = Collections.min(numbers);
int max = Collections.max(numbers);
System.out.println("Min: " + min + ", Max: " + max);
// Synchronisation
List<Integer> synchronizedList = Collections.synchronizedList(numbers);
System.out.println("Synchronized List: " + synchronizedList);
// Collections non modifiables
List<Integer> unmodifiableList = Collections.unmodifiableList(numbers);
System.out.println("Unmodifiable List: " + unmodifiableList);
}
}
Ce programme démontre le tri, la recherche, l’inversion, la recherche des valeurs minimales et maximales, la synchronisation et la création d’une liste non modifiable en utilisant la classe utilitaire Collections
.
Conclusion
Dans cet article, vous avez appris sur le Framework des Collections Java et comment il aide à gérer des groupes d’objets dans les applications Java. Nous avons exploré divers types de collections comme les Listes, Ensembles, Files et Maps et avons acquis un aperçu de certaines des caractéristiques clés et comment chacun de ces types les supporte.
Vous avez appris sur les performances, la synchronisation et les méthodes clés, acquérant des informations précieuses pour choisir les bonnes structures de données selon vos besoins.
En comprenant ces concepts, vous pouvez pleinement utiliser le Framework des Collections Java, ce qui vous permet d’écrire un code plus efficace et de construire des applications robustes.
Si vous avez trouvé cet article intéressant, n’hésitez pas à consulter mes autres articles sur freeCodeCamp et à me contacter sur LinkedIn.
Source:
https://www.freecodecamp.org/news/java-collections-framework-reference-guide/