Vous êtes sur la page 1sur 9

POO Avancée : PROGRAMMATION OBJET

AVANCEE
Spécialité : DSI

Chapitre I : Les collections

I. Introduction

Une collection est une structure de données dynamique qui permet de gérer n'importe quel
ensemble d'éléments de même type.

Tableaux : Collections :
- Non redimensionnables - Choix de l'implémentation (complexité)
- L'insertion nécessite un décalage et de l'interface
- Les indices doivent être des entiers - Structures dynamiques
- Légers en mémoire et accès en O(1) - Algorithmes communs
- Plus gourmandes en mémoire

II. Les types des collections


La figure suivante illustre la hiérarchie des interfaces des collections en JAVA

Figure1- Java Collection Interfaces

Les classes et les interfaces de gestion de collections se situent dans le paquetage java.util.
Les collections implémentent toutes une interface. Celle-ci comprend un ensemble de
méthodes (dont certaines sont optionnelles) visant la gestion des collections. Il existe trois
grandes familles de collections, chacune définie par une interface de base :

• Les listes (interface List) sont des structures capables de contenir des objets de
différents types accessibles séquentiellement. 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 ensembles (interface Set) sont des structures contenant des éléments non dupliqués
dont l'accès reste très performant. Les objets de types Set sont donc un peu plus
restrictifs (pas de doublons) ce qui est pratique pour une liste d'éléments uniques, par
exemple.
• Les tableaux associatifs (interface Map) sont des structures qui permettent de lier un
objet clé à un autre objet valeur. Elles fonctionnent avec un système « clé - valeur »
pour ranger et retrouver les objets qu'elles contiennent

1
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

III. Les listes et les ensembles (List & Set)

Figure2- Java Collection interfaces and concrete classes

III.1 Les Listes (List)


Cette interface est implémentée par un certain nombre de collections, et garantit que ces
classes implémenteront l'ensemble des méthodes. Elle dérive de l'interface Collection. Les
éléments sont indexés (i.e. numérotés de la même façon qu'un tableau est indicé).

Méthodes sur les listes


Type Méthode Rôle
boolean add(int index, Object o) Ajouter un objet à l'index indiqué.
boolean addAll(int index, Collection c) Ajouter tous les objets d'une autre collection à l'index indiqué.
Object get(int index) Retourner l'objet à l'index indiqué.
int indexOf(Object o) Retourner le premier index de l'objet indiqué.
int lastIndexOf(Object o) Retourner le dernier index de l'objet indiqué.
Object remove(int index) Supprimer l'objet à l'index indiqué.
Remplacer l'objet à l'index indiqué. L'objet précédent est
Object set(int index, Object o)
retourné.
int size() Retourner le nombre d'éléments de la liste.

2
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

Type Méthode Rôle


subList(int fromIndex,int
List Retourner une sous-liste de celle-ci.
toIndex)

➔ Les différentes implémentations


• ArrayList (Tableau redimensionnable) Cette classe est un tableau dont la taille croit
lorsque des éléments sont ajoutés.
Exemple :

public static void main(String[] args) {

ArrayList<String> maListe = new ArrayList<String>();


maListe.add("Departement_Informatique");
maListe.add("Departement_Mecanique");
maListe.add("Departement_electrique");
maListe.add(null);

System.out.println(maListe.get(0));
System.out.println(maListe.get(1));
System.out.println(maListe.get(2));
}

• Vector (Tableau redimensionnable) Cette classe a été créée avant la classe ArrayList.
C’est un tableau dont la taille croit lorsque des éléments sont ajoutés.
NB : Cette classe est "thread-safe", c'est-à-dire que plusieurs processus peuvent
l'utiliser en même temps sans risque.
• LinkedList (Listes chaînées) Cette classe implémente l'interface List en chaînant les
éléments (liste doublement chaînée). C’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é 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 schéma qui permet de mieux comprendre le
fonctionnement de cet objet :

Figure 2 : Fonctionnement de la LinkedList

3
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

Les méthodes ajoutées sont :


Type Méthode Rôle
void addFirst(Object o) Ajoute un élément en début de liste

void addLast(Object o) Ajoute un élément en fin de liste.

Object getFirst() Retourne l'élément en début de liste.

Object getLast() Retourne l'élément en fin de liste

Object removeFirst() Supprime et retourne l'élément en début de liste

Object removeLast() Supprime et retourne l'élément en fin de liste

Exemple :

public static void main(String[] args) {

List maListe=new LinkedList() ; // on crée notre liste chaînée


maListe.add(new Integer(1)) ; // on ajoute l'entier 1 à la liste
maListe.add(new Integer(2)); // on ajoute l'entier 2 à la liste
maListe.add(new Float(2.15)) ; // on ajoute le flottant 2.15 à la
// liste
/* On remarque ici que l'entier 1 est la tête de la liste, et que le flottant
est la queue de la liste. */

System.out.println("first: "+maListe.getFirst()+" Last: "


+maListe.getLast());

Remarque importante:

LinkedList VS ArrayList/Vector:
Contrairement aux LinkedList, les ArrayList/ Vector 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, si vous effectuez beaucoup de lectures sans vous
soucier de l'ordre des éléments, optez pour une ArrayList ou un Vector ; en revanche, si vous
insérez beaucoup de données au milieu de la liste, optez pour une Linkedlist.

III.2 Les Ensembles (Set)


Conformément à l'idée mathématique, les ensembles représentent plusieurs éléments non
triés, sans répétitions. Les ajouts d'éléments déjà présents sont donc ignorés (objets comparés
par la méthode equals). Cette interface dérive de l'interface Collection, sans ajouter de
nouvelles méthodes.
➔ Les différentes implémentations
• HashSet : La classe HashSet implémente l'interface Set en utilisant une table de hachage.
C'est l’implémentation la plus utilisée de l'interface Set

4
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

• LinkedHashSet : diffère de HashSet car elle maintient une liste doublement liée à travers
toutes ses entrées, permettant de retrouver l'ordre d'insertion.
• TreeSet : Les ensembles triés sont identiques aux ensembles simples excepté qu'ils
peuvent être triés par défaut à leur création. Cette classe implémente l’interface SortedSet
et utilise un arbre de recherche. Pour pouvoir utiliser un TreeSet, il faut que les éléments
soit comparables.
Remarque : 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 une 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.

III.3 Les collections génériques


Avant la version 5 de Java, les collections ne permettaient que de stocker des instances de la
classe Object sans pouvoir mieux préciser le type des éléments :
LinkedList maListe = new LinkedList();

Depuis la version 5, nous pouvons préciser le type des éléments contenus dans la collection
(si tous les éléments sont de même type) en écrivant :
LinkedList<Integer> maListe = new LinkedList<Integer>();

III.4 Comment parcourir une collection?


Pour parcourir et afficher le contenue des collections, il est possible d’utiliser
• Les Itérateurs : ce sont objets qui permettent de parcourir les collections. En plus de
l'interface Collection, les classes List et Set et Queue étendent l'interface Iterator.
Le principe est simple : on récupère un itérateur positionné avant le premier élément
de la collection par la méthode iterator(), on navigue de proche en proche par la
méthode next() de l’itérateur en s’assurant qu’il existe des éléments suivants par
hasNext()
Par exemple, le parcours d'une liste nommée maListe peut se faire de la manière
suivante :
Iterator iterateur= maListe.listIterator();
while (iterateur.hasNext())
System.out.println(iterateur.next());

Remarque : les Maps n'implémentant pas l'interface Iterable, ils ne permettent pas d'être
parcourus à l'aide d'un itérateur
• La boucle FOR-EACH : La version 5 de Java introduit une nouvelle boucle qui
simplifie le parcours d’une collection : la boucle for-each.
Par exemple, le parcours d'une liste d’entiers, nommée maListe peut se faire de la
manière suivante

for (Integer entier : maListe)


System.out.println( entier) ;

Cette boucle est d’un usage très intuitif. Cependant, on remarquera qu’il n’est pas possible de
supprimer des éléments de la collection si on la parcoure avec un for-each.

• Parcours simple (Seulement pour les listes)

5
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

Il est possible de parcourir une collection de type liste, de la même façon (ou presque) qu’on
parcoure un tableau. Par exemple, le parcours d'une liste d’entiers, nommée maListe peut se
faire de la manière suivante :

for (int i = 0; i < maListe.size(); i++)


System.out.println(maListe.get(i));

Exemple complet :

public class TestParcoursCollection {

public static void main(String[] args) {

LinkedList<String> maListe = new LinkedList<String>();


maListe.add("Bonjour =)!");
maListe.add("ISET Beja");;

// Parcours simple: Seulement pour les collections de type Liste


for (int i = 0; i < maListe.size(); i++) {
System.out.println(maListe.get(i));
}

// Parcours avec For-Each


for (Integer entier : maListe)
System.out.println( entier) ;

// Parcours avec un itérateur


Iterator<String> iterator = maListe.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}

}
}

III.5 Les méthodes de la classe Collections


La classe Collections définit des méthodes statiques qui seront utilisées pour réaliser
différents traitements sur les collections. Certaines de ces méthodes ne s'appliquent que sur
des listes ; c'est le cas de:
• sort : trie les éléments de la liste dans l'ordre naturel
• shuffle : ordonne de manière aléatoire les éléments de la liste
• reverse : inverse l'ordre des éléments de la liste
• fill : réinitalise la liste avec une valeur définie
• copy : copie une liste dans une autre.

IV. Les tableaux associatifs (Map)


Un autre type de structure de données utilisable en Java est le Map. Une map permet de créer
un ensemble de couples clé/valeur (On parle aussi de tableaux associatifs), la clé permettant

6
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

de retrouver rapidement la valeur qui lui a été associée. Les clés sont des objets uniques
pouvant être NULL; Les valeurs peuvent être multiples et NULL.
On retrouve principalement quatre classes qui implémentent l'interface Map : HashTable,
HashMap, LinkedHashMap et TreeMap.

Figure3 - JAVA Map interface and concrete classes

Les principales méthodes de cette interface sont :


Type Méthode Rôle
void clear() Vider la collection.
boolean containsKey(Object key) Teste si la clé existe, c'est à dire associée à une valeur.

boolean containsValue(Object value) Teste si la valeur existe.

Set entrySet() Retourne l'ensemble des associations clés-valeurs

Set keySet() Retourne l'ensemble des clés.

Collection values() Retourne la collection de valeurs

Object Associe la clé à la valeur spécifiée, et retourne la valeur


put(Object key, Object value) précédemment associée.
boolean putAll(Map m) Ajouter tous les objets d'une autre collection à celle-ci.

Object Retourne la valeur associée à la clé spécifiée, ou null si


get(Object key) non trouvé.

7
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

Type Méthode Rôle


Object remove(Object key) Supprime l'objet associé à la clé, et retourne cet objet.

Boolean isEmpty() Tester si la collection est vide.

int size() Retourne le nombre de clés.

➔ Les différentes implémentations


• HashMap : C’est l'implémentation concrète la plus standard, elle est adaptée à la
plupart des situations. Elle accepte la valeur null et elle n'est pas Thread Safe
• HashTable : Cette classe ne diffère que très peu de la HashMap. Elle implémente
l'interface Map de manière synchronisée (Thread Safe) et n’accepte pas la valeur null.
• LinkedHashMap : HashTable + Liste chainée
• TreeMap : Similaire à SortedSet. La classe TreeMap ajoute une fonction de tri des
clés de la Map. L'ordre des clés peut être choisi en donnant une instance de
java.util.Comparator sinon c'est l'ordre naturel des clés qui sera utilisé.

Comment instancier une Map ?

Map<TypeClefs,TypeValeurs> map = new ClasseImplMap<TypeClefs,TypeValeurs>

Comment parcourir une Map ?


On peut parcourir une collection de type Map au moyen d'Iterator. Pour cela, il suffit de
récupérer soit les clefs avec la méthode keySet() soit les valeurs avec la méthode values() et
d'appeler ensuite la méthode iterator() sur la collection

Exemple :

public class TestMap {

public static void main(String[] args) {


HashMap<Integer,String> map = new HashMap<Integer,String>() ;

map.put(1, "Bonjour");
map.put(2, "Bonsoir");
map.put(3, "Bonne journée");

// Parcours de valeurs
for (Iterator<String> i = map.values().iterator() ; i.hasNext() ;)
System.out.println(i.next());

// Parcours de clefs
for (Iterator<Integer> i = map.keySet().iterator() ; i.hasNext() ; )
System.out.println(i.next());
}
}

8
POO Avancée : PROGRAMMATION OBJET
AVANCEE
Spécialité : DSI

Les objets Maps 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.

Résumé et comparatif :

Type Classe Description


Les listes ArrayList
représente un tableau dynamique dont la taille peut varier.
Vector représente un tableau dynamique dont la taille peut varier et
dont les valeurs ne peuvent être nulles. Thread-safe
LinkedList représente une liste doublement chainée. Cette classe peut
être utilisable comme une pile LIFO ou une file FIFO.
Queue représente un mécanisme de pile de type FIFO.
Ensembles HashSet représente une table de hachage.
LinkedHashSet représente une table de hachage avec une liste chainée
TreeSet représente un ensemble classant les objets en ordre naturel
croissant.
Les Maps HashMap représente un tableau associatif dont une clé et des valeurs
peuvent être nulles.
Hashtable représente un tableau associatif dont les clés ne peuvent
être nulles. Thread-safe.
LinkedHashMap représente un tableau associatif sous forme d’une liste
doublement chainée.
TreeMap représente un tableau associatif dont les clés sont classées
en ordre naturel croissant (selon les clés).

ArrayList Vector LinkedList HashSet LinkedHashSet TreeSet Hashtable LinkedHashMap HashMap TreeMap
Null √ √ √ √ √ X X √ √ √
Duplicate √ √ √ X X X X X X X
Sorted
Result
X X X X X √ X X X √
Retrieval
order
same as √ √ √ X √ X X √ X X
insertion

Vous aimerez peut-être aussi