Voici un chapitre qui va particulièrement vous plaire. Nous allons voir que nous ne sommes pas obligés de stocker nos données dans des tableaux ! Ces fameuses collections d'objets sont d'ailleurs dynamiques : en gros, elles n'ont pas de taille prédéfinie. Il est donc impossible de dépasser leur capacité !
Je ne passerai pas en revue tous les types et tous les objets Collection
car ils sont nombreux, mais nous verrons les principaux d'entre eux. Les objets que nous allons aborder ici sont tous dans le package java.util
. Facile à retenir, non ?
Ce chapitre vous sera d'une grande utilité, car les collections sont primordiales dans les programmes Java.
Les différents types de collections
Avant de vous présenter certains objets, je me propose de vous présenter la hiérarchie d'interfaces composant ce qu'on appelle les collections. Oui, vous avez bien lu, il s'agit bien d'interfaces : celles-ci encapsulent la majeure partie des méthodes utilisables avec toutes les implémentations concrètes. Voici un petit diagramme de classes sur la figure suivante schématisant cette hiérarchie.
Vous pouvez voir qu'il existe plusieurs types de collections, que les interfaces List
et Set
implémentent directement l'interface Collection
et que l'interface Map
gravite autour de cette hiérarchie, tout en faisant partie des collections Java.
En lisant la suite de ce chapitre, vous constaterez que ces interfaces ont des particularités correspondant à des besoins spécifiques. Les objets de type List
servent à stocker des objets sans condition particulière sur la façon de les stocker. Ils acceptent toutes les valeurs, même les valeurs null
. Les types Set
sont un peu plus restrictifs, car ils n'autorisent pas deux fois la même valeur (le même objet), ce qui est pratique pour une liste d'éléments uniques, par exemple. Les Map
sont particulières, car elles fonctionnent avec un système clé - valeur pour ranger et retrouver les objets qu'elles contiennent.
Maintenant que je vous ai brièvement expliqué les différences entre ces types, voyons comment utiliser ces objets.
Les objets List
Les objets appartenant à la catégorie List
sont, pour simplifier, des tableaux extensibles à volonté. On y trouve les objets Vector
, LinkedList
et ArrayList
. Vous pouvez y insérer autant d'éléments que vous le souhaitez sans craindre de dépasser la taille de votre tableau. Ils fonctionnent tous de la même manière : vous pouvez récupérer les éléments de la liste via leurs indices. De plus, les List
contiennent des objets. Je vous propose de voir deux objets de ce type qui, je pense, vous seront très utiles.
L'objet LinkedList
Une liste chaînée (LinkedList en anglais) est une liste dont chaque élément est lié aux éléments adjacents par une référence à ces derniers. Chaque élément contient une référence à l'élément précédent et à l'élément suivant, exceptés le premier, dont l'élément précédent vaut null
, et le dernier, dont l'élément suivant vaut également null
.
La figure suivante représente un un schéma qui vous permettra de mieux vous représenter le fonctionnement de cet objet :
Voici un code pour appuyer mes dires :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import java.util.LinkedList; import java.util.List; import java.util.ListIterator; public class Test { public static void main(String[] args) { List l = new LinkedList(); l.add(12); l.add("toto ! !"); l.add(12.20f); for(int i = 0; i < l.size(); i++) System.out.println("Élément à l'index " + i + " = " + l.get(i)); } } |
Si vous essayez ce code, vous constaterez que tous les éléments s'affichent !
Il y a autre chose que vous devez savoir sur ce genre d'objet : ceux-ci implémentent l'interface Iterator
. Ainsi, nous pouvons utiliser cette interface pour lister notre LinkedList
.
Un itérateur est un objet qui a pour rôle de parcourir une collection. C'est d'ailleurs son unique raison d'être. Pour être tout à fait précis, l'utilisation des itérateurs dans Java fonctionne de la même manière que le pattern du même nom. Tout comme nous avons pu le voir avec la pattern strategy, les design patterns sont en fait des modèles de conception d'objets permettant une meilleure stabilité et une réutilisabilité accrue. Les itérateurs en font partie.
Dans le code suivant, j'ai ajouté le parcours avec un itérateur :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import java.util.LinkedList; import java.util.List; import java.util.ListIterator; public class Test { public static void main(String[] args) { List l = new LinkedList(); l.add(12); l.add("toto ! !"); l.add(12.20f); for(int i = 0; i < l.size(); i++) System.out.println("Élément à l'index " + i + " = " + l.get(i)); System.out.println("\n \tParcours avec un itérateur "); System.out.println("-----------------------------------"); ListIterator li = l.listIterator(); while(li.hasNext()) System.out.println(li.next()); } } |
Les deux manières de procéder sont analogues !
Attention, je dois vous dire quelque chose sur les listes chaînées : vu que tous les éléments contiennent une référence à l'élément suivant, de telles listes risquent de devenir particulièrement lourdes en grandissant ! Cependant, elles sont adaptées lorsqu'il faut beaucoup manipuler une collection en supprimant ou en ajoutant des objets en milieu de liste. Elles sont donc à utiliser avec précaution.
L'objet ArrayList
Voici un objet bien pratique. ArrayList
est un de ces objets qui n'ont pas de taille limite et qui, en plus, acceptent n'importe quel type de données, y compris null
! Nous pouvons mettre tout ce que nous voulons dans un ArrayList
, voici un morceau de code qui le prouve :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayList al = new ArrayList(); al.add(12); al.add("Une chaîne de caractères !"); al.add(12.20f); al.add('d'); for(int i = 0; i < al.size(); i++) { System.out.println("donnée à l'indice " + i + " = " + al.get(i)); } } } |
Si vous exécutez ce code, vous obtiendrez la figure suivante.
Je pense que vous voyez déjà les avantages des ArrayList
.
Sachez aussi qu'il existe tout un panel de méthodes fournies avec cet objet :
add()
permet d'ajouter un élément ;get(int index)
retourne l'élément à l'indice demandé ;remove(int index)
efface l'entrée à l'indice demandé ;isEmpty()
renvoie « vrai » si l'objet est vide ;removeAll()
efface tout le contenu de l'objet ;contains(Object element)
retourne « vrai » si l'élément passé en paramètre est dans l'ArrayList
.
Contrairement aux LinkedList
, les ArrayList
sont rapides en lecture, même avec un gros volume d'objets. Elles sont cependant plus lentes si vous devez ajouter ou supprimer des données en milieu de liste. Pour résumer à l'extrême, si vous effectuez beaucoup de lectures sans vous soucier de l'ordre des éléments, optez pour une ArrayList
; en revanche, si vous insérez beaucoup de données au milieu de la liste, optez pour une Linkedlist
.
Les objets Map
Une collection de type Map
est une collection qui fonctionne avec un couple clé - valeur. On y trouve les objets Hashtable
, HashMap
, TreeMap
, WeakHashMap
… La clé, qui sert à identifier une entrée dans notre collection, est unique. La valeur, au contraire, peut être associée à plusieurs clés.
Ces objets ont comme point faible majeur leur rapport conflictuel avec la taille des données à stocker. En effet, plus vous aurez de valeurs à mettre dans un objet Map
, plus celles-ci seront lentes et lourdes : logique, puisque par rapport aux autres collections, il stocke une donnée supplémentaire par enregistrement. Une donnée c'est de la mémoire en plus et, même si les ordinateurs actuels en ont énormément, gardez en tête que « la mémoire, c'est sacré » (je vous rappelle que les applications Java ne sont pas forcément destinées aux appareils bénéficiant de beaucoup de mémoire).
L'objet Hashtable
Vous pouvez également dire « table de hachage », si vous traduisez mot à mot… On parcourt cet objet grâce aux clés qu'il contient en recourant à la classe Enumeration
. L'objet Enumeration
contient notre Hashtable
et permet de le parcourir très simplement. Regardez, le code suivant insère les quatre saisons avec des clés qui ne se suivent pas, et notre énumération récupère seulement les valeurs :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import java.util.Enumeration; import java.util.Hashtable; public class Test { public static void main(String[] args) { Hashtable ht = new Hashtable(); ht.put(1, "printemps"); ht.put(10, "été"); ht.put(12, "automne"); ht.put(45, "hiver"); Enumeration e = ht.elements(); while(e.hasMoreElements()) System.out.println(e.nextElement()); } } |
Cet objet nous offre lui aussi tout un panel de méthodes utiles :
isEmpty()
retourne « vrai » si l'objet est vide ;contains(Object value)
retourne « vrai » si la valeur est présente. Identique àcontainsValue(Object value)
;containsKey(Object key)
retourne « vrai » si la clé passée en paramètre est présente dans laHashtable
;put(Object key, Object value)
ajoute le couplekey - value
dans l'objet ;elements()
retourne une énumération des éléments de l'objet ;keys()
retourne la liste des clés sous forme d'énumération.
De plus, il faut savoir qu'un objet Hashtable
n'accepte pas la valeur null
et qu'il est Thread Safe
, c'est-à-dire qu'il est utilisable dans plusieurs threads (cela signifie que plusieurs éléments de votre programme peuvent l'utiliser simultanément ; nous y reviendrons) simultanément sans qu'il y ait un risque de conflit de données.
L'objet HashMap
Cet objet ne diffère que très peu de la Hashtable
:
- il accepte la valeur
null
; - il n'est pas
Thread Safe
.
En fait, les deux objets de type Map
sont, à peu de choses près, équivalents.
Les objets Set
Un Set
est une collection qui n'accepte pas les doublons. Par exemple, elle n'accepte qu'une seule fois null
, car deux valeurs null
sont considérées comme un doublon. On trouve parmi les Set
les objets HashSet
, TreeSet
, LinkedHashSet
… Certains Set
sont plus restrictifs que d'autres : il en existe qui n'acceptent pas null
, certains types d'objets, etc.
Les Set
sont particulièrement adaptés pour manipuler une grande quantité de données. Cependant, les performances de ceux-ci peuvent être amoindries en insertion. Généralement, on opte pour un HashSet
, car il est plus performant en temps d'accès, mais si vous avez besoin que votre collection soit constamment triée, optez pour un TreeSet
.
L'objet HashSet
C'est sans nul doute la plus utilisée des implémentations de l'interface Set
. On peut parcourir ce type de collection avec un objet Iterator
ou extraire de cet objet un tableau d'Object
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import java.util.HashSet; import java.util.Iterator; public class Test { public static void main(String[] args) { HashSet hs = new HashSet(); hs.add("toto"); hs.add(12); hs.add('d'); Iterator it = hs.iterator(); while(it.hasNext()) System.out.println(it.next()); System.out.println("\nParcours avec un tableau d'objet"); System.out.println("-----------------------------------"); Object[] obj = hs.toArray(); for(Object o : obj) System.out.println(o); } } |
Voici une liste des méthodes que l'on trouve dans cet objet :
add()
ajoute un élément ;contains(Object value)
retourne « vrai » si l'objet contientvalue
;isEmpty()
retourne « vrai » si l'objet est vide ;iterator()
renvoie un objet de typeIterator
;remove(Object o)
retire l'objeto
de la collection ;toArray()
retourne un tableau d'Object
.
Voilà ! Nous avons vu quelque chose d'assez intéressant que nous pourrons utiliser dans peu de temps, mais avant, nous avons encore du pain sur la planche. Dans le chapitre suivant nous verrons d'autres aspects de nos collections.
- Une collection permet de stocker un nombre variable d'objets.
- Il y a principalement trois types de collection : les
List
, lesSet
et lesMap
. - Chaque type a ses avantages et ses inconvénients.
- Les
Collection
stockent des objets alors que lesMap
stockent un couple clé - valeur. - Si vous insérez fréquemment des données en milieu de liste, utilisez une
LinkedList
. - Si vous voulez rechercher ou accéder à une valeur via une clé de recherche, optez pour une collection de type
Map
. - Si vous avez une grande quantité de données à traiter, tournez-vous vers une liste de type
Set
.