2. Interface Collection

2.1. Notion de Collection

Dans le cadre de l'API Collection, une collection d'objets est juste un ensemble d'objets. La notion d'ordre n'est pas définie, ni entre les objets stockés (on ne peut pas dire qu'un objet est plus grand qu'un autre), ni dans le temps (on ne peut pas dire si un objet a été rangé dans cette collection avant un autre). Les opérations que l'on peut définir sur un tel ensemble sont basiques :
  • on peut y ajouter des objets, un par un ou par paquets ;
  • on peut retirer des objets précis, un par un ou par paquets ;
  • on peut tester si un objet appartient à cet ensemble ;
  • on peut balayer l'ensemble de ces objets, mais sans prévoir l'ordre dans lequel les objets contenus seront balayés ;
  • on peut déterminer le cardinal de cet ensemble ;
  • on peut en effacer le contenu.
L’interface Collection est parente de trois autres interfaces : List, Set et sa descendante SortedSet que nous verrons dans la suite.

2.2. Détail des méthodes disponibles

Examinons le détail des méthodes disponibles sur ces ensembles.
  • size() et isEmpty() : retourne le nombre d'éléments portés par cette collection, et un booléen qui permet de tester si cette collection est vide ou pas.
  • contains(T t) : retourne true si l'objet passé en paramètre est contenu dans cette collection.
  • add(T t) et remove(T t) : permet d'ajouter (resp. de retirer) un objet à cette collection.
  • iterator() : retourne un itérateur sur les éléments de cette collection.
  • addAll(Collection<? extends T> collection) et removeAll(Collection<? extends T> collection) : permet d'ajouter (resp. de retirer) l'ensemble des objets passés dans la collection en paramètre.
  • retainAll(Collection<? extends T> collection) : permet de retirer tous les éléments de la collection qui ne se trouvent pas dans la collection passée en paramètre. Cette opération réalise l'intersection des deux collections.
  • containsAll(Collection<? extends T> collection) : retourne true si tous les éléments de la collection passée en paramètre se trouvent dans la collection courante. Cette opération teste l'inclusion.
  • clear() : efface la collection courante.
  • toArray(T[] a) : convertit la collection courante en tableau.

2.3. Interface Iterator

La méthode iterator() de l'interface Collection retourne une instance d' Iterator. Cette interface est très simple, et n'expose que trois méthodes :
  • hasNext() : retourne true si la collection possède encore des éléments à itérer ;
  • next() : retourne l'élément suivant ;
  • remove() : permet de retirer de la collection l'élément courant. Cette opération est optionnelle, et peut ne pas être supportée par toutes les implémentations. Si une implémentation ne supporte pas cette méthode, alors elle doit jeter l'exception UnsupportedOperationException.

2.4. Implémentation, exemples d'utilisation

Il n'y a pas d'implémentation exclusive de l'interface Collection dans l'API Java. La classe utilisée le plus souvent est ArrayList, qui est également implémentation de List. Voyons l'utilisation de cette classe sur un exemple simple.

2.4.1. Créer une collection de String

La création d'une collection consiste en son instanciation, et l'utilisation de sa méthode add(T). Voyons ceci sur un exemple.

Exemple 1. Création d'une collection de String

// création d'une collection de String
Collection<String> collection =  new ArrayList<String>() ;

 // ajout d'éléments à cette collection
collection.add("un") ;
collection.add("deux") ;
collection.add("trois") ;

Notons que l'on n'a pas à se soucier des problèmes de dépassement de capacité. La capacité d'une collection est censée être infinie (enfin presque...). Si l'implémentation choisie est construite sur un tableau, ce qui est le cas ici, la saturation de ce tableau doit être gérée de façon transparente par la classe d'implémentation. C'est d'ailleurs le cas ici.

2.4.2. Test d'appartenance d'un objet à une collection

L'interface Collection expose une méthode contains(T) qui nous permet de tester si un objet précis appartient à une collection.

Exemple 2. Test d'appartenance d'un objet à une collection

// test d'appartenance de "deux"
 boolean b1 = collection.contains("deux") ;
System.out.println(b1) ;  // affiche true

 // test d'appartenance de "DEUX"
 boolean b2 = collection.contains("DEUX") ;
System.out.println(b2) ;  // affiche false

Dans le cas de ArrayList cette méthode appelle la méthode equals() de l'objet passé en paramètre, pour tous les objets de la collection. Elle est donc éventuellement coûteuse.

2.4.3. Parcourir les éléments d'une collection

Il existe deux façons de faire pour parcourir les éléments d'une collection. La première consiste à créer un itérateur sur la collection, et à l'utiliser.

Exemple 3. Parcourir les éléments d'une collection avec un itérateur

// parcourir les éléments de la collection avec
 // un itérateur
Iterator<String> it = collection.iterator() ;
 while (it.hasNext()) {
	
    String element = it.next() ;  // retourne un objet de type String
    System.out.println(element) ;
}

La seconde consiste à utiliser la nouvelle syntaxe for each , introduite en Java 5.

Exemple 4. Parcourir les éléments d'une collection avec un for each

// balayer les éléments de la collection avec
 // un for each
 for (String element : collection) {
	
    System.out.println(element) ;
}

Cette seconde syntaxe est beaucoup plus légère et lisible que la première. Elle est largement suffisante lorsque l'on veut juste parcourir ses éléments. Dans les cas où l'on a besoin d'interagir avec le contenu de la collection au travers de l'itérateur, elle n'est pas utilisable.

2.4.4. Conversion d'une collection en tableau

Enfin, on peut créer un tableau à partir des éléments contenus dans une collection.

Exemple 5. Conversion d'une collection en tableau

// pattern de conversion d'une collection en tableau
String [] tab = collection.toArray(new String[] {}) ;

 // affichage du contenu du tableau
 for (String element : tab) {
	
    System.out.println(element) ;
}

Java API avancées
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
API Collection
1. Introduction
2. Interface Collection
2.1. Notion de Collection
2.2. Détail des méthodes disponibles
2.3. Interface Iterator
2.4. Implémentation, exemples d'utilisation
3. Interface List
3.1. Notion de List
3.2. Détail des méthodes disponibles
3.3. Interface ListIterator
3.4. Implémentations, exemples d'utilisation
4. Interface Set
4.1. Notion de Set
4.2. Implémentations HashSet et LinkedHashSet
4.3. Exemples d'utilisation
5. Interface SortedSet
5.1. Notion de SortedSet
5.2. Détails des méthodes disponibles
5.3. Exemples d'utilisation
6. Interface NavigableSet
6.1. Notion de NavigableSet
6.2. Détails des méthodes disponibles
6.3. Exemple d'utilisation
7. Interfaces Queue et Deque
7.1. Notion de file d'attente
7.2. Détail des méthodes disponibles
7.3. Utilisation des interfaces Queue et Deque
8. Tables de hachage
8.1. Notion de table de hachage
8.2. Interface Map
8.3. Interface Map.Entry
8.4. Interface SortedMap
8.5. Interface NavigableMap
8.6. Implémentations
8.7. Exemples d'utilisation
9. Classes utilitaires Collections et Arrays
9.1. Introduction
9.2. Classe Arrays
9.3. Classe Collections
Génériques
1. Introduction
2. Un premier exemple
2.1. Une première classe générique
2.2. Une première méthode générique
3. Contraindre un type générique
3.1. Problème posé
3.2. Contraindre un type générique
4. Implémentation des génériques
4.1. Type erasure
4.2. Types génériques et casts
4.3. Type générique et exception
4.4. Construction d'une instance générique
4.5. Génériques et membres statiques
4.6. Collisions de méthodes génériques
4.7. Implémentation de plusieurs types identiques
5. Type <?>
5.1. Introduction
5.2. Type ? extension d'un type
5.3. Type ? super-type d'un type
Expressions régulières
1. Introduction
2. Mise en œuvre des expressions régulières
2.1. Fonctionnement d'une regexp
2.2. Fonctionnement de l'API en Java
2.3. Un premier exemple
2.4. Classe Pattern
2.5. Classe Matcher
2.6. Utilisation des méthode find() et group()
2.7. Méthodes de remplacement
2.8. Sélection de régions
3. Syntaxe des expressions régulières
3.1. Notion de classe
3.2. Étude d'un cas réel
3.3. Recherche d'un mot précis
3.4. Recherche de deux mots précis
3.5. Recherche d'un mot commençant par une lettre donnée
3.6. Cas de mots comportant des caractères accentués
3.7. Recherche sur les lignes
Introspection
1. Introduction
2. La classe Class
2.1. Utilisation de Class
2.2. Méthodes disponibles
2.3. Remarque sur la propriété Accessible
2.4. Type d'une classe
2.5. Création d'une instance à partir d'un objet Class
2.6. Cas des énumérations
3. Les classes Method et Constructor
3.1. Utilisation de Method
3.2. Utilisation de Constructor
3.3. Méthodes disponibles
3.4. Invocation d'une méthode par introspection
4. La classe Field
4.1. Utilisation de Field
4.2. Méthodes disponibles
4.3. Accès à un champ par introspection
5. La classe Modifier
Programmation concurrente
1. Introduction
2. Lançons nos premiers threads
2.1. Introduction
2.2. Un premier thread, extension de Thread
2.3. Un deuxième thread, implémentation de Runnable
2.4. Remarque sur la méthode Thread.sleep(long)
2.5. Arrêter un thread
3. Concurrence d'accès
3.1. Notion d'état
3.2. Exemple de concurrence d'accès sur un état
3.3. Analyse de la concurrence d'accès
3.4. Solution au problème
3.5. Champs volatile
4. Synchronisation
4.1. Définition d'un bloc synchronisé
4.2. Fonctionnement d'un bloc synchronisé
4.3. Notion de deadlock
4.4. Bonnes pratiques pour la synchronisation de threads
5. Opérations atomiques
5.1. Atomicité d'une opération
5.2. Solutions disponibles
5.3. Variables atomiques
6. Collections synchronisées et concurrentes
6.1. Introduction
6.2. Position du problème
6.3. Solutions proposées
7. Files d'attente
7.1. Introduction, pattern producteur / consommateur
7.2. Interface BlockingQueue<E>
7.3. Implémentations de BlockingQueue
7.4. Exemple de producteur / consommateur
7.5. Arrêter un producteur / consommateur : pilule empoisonnée
8. Classes utilitaires de l'API Concurrent
8.1. Introduction
8.2. Énumération TimeUnit
8.3. Interface Callable<V>
8.4. Interfaces Future<V> et RunnableFuture<V>
8.5. Interface ScheduledFuture<V> et RunnableScheduledFuture<V>
9. Pattern executor
9.1. Notion de réserve de threads
9.2. Interface Executor
9.3. Interface ExecutorService
9.4. Interface ScheduledExecutorService
9.5. Classe Executors
9.6. Pattern de lancement de tâches
10. Classes de contrôle d'accès
10.1. Introduction
10.2. Interfaces Lock et ReadWriteLock
10.3. Notion de verrou réentrant
10.4. Classe RentrantLock
10.5. Classe ReadWriteRentrantLock
11. Sémaphores, barrières et latches
11.1. Introduction
11.2. Notion de sémaphore, classe Semaphore
11.3. Notion de latch, classe CountDownLatch
11.4. Notion de barrière, classe CyclicBarrier