Premiers pas avec le Java Collections Framework

JDK 1.2 introduit un nouveau cadre pour les collections d'objets, appelé Java Collections Framework. "Oh non," vous gémissez, "pas une autre API, pas un autre framework à apprendre!" Mais attendez, avant de vous détourner, écoutez-moi: le framework Collections vaut votre effort et profitera à votre programmation à bien des égards. Trois grands avantages viennent immédiatement à l'esprit:

  • Il augmente considérablement la lisibilité de vos collections en fournissant un ensemble standard d'interfaces à utiliser par de nombreux programmeurs dans de nombreuses applications.
  • Cela rend votre code plus flexible en vous permettant de passer et de renvoyer des interfaces au lieu de classes concrètes, généralisant votre code plutôt que de le verrouiller.
  • Il propose de nombreuses implémentations spécifiques des interfaces, vous permettant de choisir la collection la plus adaptée et offrant les performances les plus élevées pour vos besoins.

Et ce n'est que pour les débutants.

Notre visite du framework commencera par un aperçu des avantages qu'il offre pour stocker des ensembles d'objets. Comme vous allez bientôt découvrir, parce que vos vieux amis cheval de bataille Hashtableet Vectorprennent en charge la nouvelle API, vos programmes seront uniformes et concis - quelque chose que vous et les développeurs accédant à votre code certainement se réjouir.

Après notre discussion préliminaire, nous approfondirons les détails.

L'avantage des collections Java: un aperçu

Avant que Collections ne fasse ses débuts les plus bienvenus, les méthodes standard de regroupement d'objets Java étaient via le tableau, le Vectoret le Hashtable. Ces trois collections ont des méthodes et une syntaxe différentes pour accéder aux membres: les tableaux utilisent les symboles entre crochets ([]), Vectorutilisent la elementAtméthode, et Hashtableutilisent getet putméthodes. Ces différences ont longtemps conduit les programmeurs sur la voie de l'incohérence dans l'implémentation de leurs propres collections - certains émulent les Vectorméthodes d'accès et d'autres émulent l' Enumerationinterface.

Pour compliquer davantage les choses, la plupart des Vectorméthodes sont marquées comme définitives; autrement dit, vous ne pouvez pas étendre la Vectorclasse pour implémenter un type de collection similaire. Nous pourrions créer une classe de collection qui ressemblait à a Vectoret agissait comme a Vector, mais elle ne pouvait pas être transmise à une méthode qui prend a Vectorcomme paramètre.

Enfin, aucune des collections (tableau Vectorou Hashtable) n'implémente une interface d'accès aux membres standard. Alors que les programmeurs développaient des algorithmes (comme des sortes) pour manipuler les collections, un discours passionné a éclaté sur quel objet passer à l'algorithme. Devriez-vous passer un tableau ou un Vector? Devez-vous implémenter les deux interfaces? Parlez de duplication et de confusion.

Heureusement, le Java Collections Framework résout ces problèmes et offre un certain nombre d'avantages par rapport à l'utilisation d'aucun framework ou à l'utilisation de Vectoret Hashtable:

  • Un ensemble d'interfaces de collecte utilisables

    En mettant en œuvre l' une des interfaces de base - Collection, Set, Listou Map- vous assurer que votre classe est conforme à une API commune et devient plus régulière et facile à comprendre. Ainsi, que vous implémentiez une base de données SQL, un nuancier de couleurs ou une application de chat à distance, si vous implémentez l' Collectioninterface, les opérations sur votre collection d'objets sont bien connues de vos utilisateurs. Les interfaces standard simplifient également le passage et le retour des collections vers et depuis les méthodes de classe et permettent aux méthodes de travailler sur une plus grande variété de collections.

  • Un ensemble de base d'implémentations de collection

    En plus des trusty Hashtableet Vector, qui ont été mis à jour pour implémenter les Collectioninterfaces, de nouvelles implémentations de collection ont été ajoutées, notamment HashSetet TreeSet, ArrayListet LinkedList, et HashMapet Map. L'utilisation d'une implémentation commune existante rend votre code plus court et plus rapide à télécharger. En outre, l'utilisation du noyau de code Java Core existant garantit que toute amélioration du code de base améliorera également les performances de votre code.

  • Autres améliorations utiles

    Chaque collection renvoie désormais un Iterator, un type amélioré de Enumerationqui permet des opérations d'élément telles que l'insertion et la suppression. Le Iteratorest "fail-fast", ce qui signifie que vous obtenez une exception si la liste que vous itérez est modifiée par un autre utilisateur. En outre, les collections basées sur des listes telles que Vectorretournent un ListIteratorqui permettent une itération et une mise à jour bidirectionnelles.

    Plusieurs collections ( TreeSetet TreeMap) prennent implicitement en charge la commande. Utilisez ces classes pour maintenir une liste triée sans effort. Vous pouvez rechercher les éléments les plus petits et les plus grands ou effectuer une recherche binaire pour améliorer les performances des grandes listes. Vous pouvez trier d'autres collections en fournissant une méthode de comparaison de collections (un Comparatorobjet) ou une méthode de comparaison d'objets (l' Comparableinterface).

    Enfin, une classe statique Collectionsfournit des versions non modifiables (lecture seule) et synchronisées des collections existantes. Les classes non modifiables sont utiles pour empêcher les modifications indésirables d'une collection. La version synchronisée d'une collection est une nécessité pour les programmes multithread.

Le Java Collections Framework fait partie de Core Java et est contenu dans le java.util.collectionspackage de JDK 1.2. Le framework est également disponible sous forme de package pour JDK 1.1 (voir Ressources).

Remarque: la version JDK 1.1 des collections est nommée com.sun.java.util.collections. Gardez à l'esprit que le code développé avec la version 1.1 doit être mis à jour et recompilé pour la version 1.2, et tous les objets sérialisés en 1.1 ne peuvent pas être désérialisés en 1.2.

Examinons maintenant de plus près ces avantages en exerçant le Java Collections Framework avec notre propre code.

Une bonne API

Le premier avantage de Java Collections Framework est une API cohérente et régulière. L'API est codifié dans un ensemble d'interfaces de base, Collection, Set, List, ou Map. L' Collectioninterface contient des opérations de collecte de base telles que l'ajout, la suppression et les tests d'appartenance (confinement). Toute implémentation d'une collection, qu'elle soit fournie par Java Collections Framework ou l'une de vos propres créations, prendra en charge l'une de ces interfaces. Étant donné que le framework Collections est régulier et cohérent, vous apprendrez une grande partie des frameworks simplement en apprenant ces interfaces.

Les deux Setet Listimplémentent l' Collectioninterface. L' Setinterface est identique à l' Collectioninterface, à l'exception d'une méthode supplémentaire toArray, qui convertit a Seten Objecttableau. L' Listinterface implémente également l' Collectioninterface, mais fournit de nombreux accesseurs qui utilisent un index entier dans la liste. Par exemple, get, removeet setprendre tout un entier qui affecte l'élément indexé dans la liste. L' Mapinterface n'est pas dérivée de la collection, mais fournit une interface similaire aux méthodes de java.util.Hashtable. Les clés sont utilisées pour mettre et obtenir des valeurs. Chacune de ces interfaces est décrite dans les exemples de code suivants.

Le segment de code suivant montre comment effectuer de nombreuses Collectionopérations sur HashSet, une collection de base qui implémente l' Setinterface. A HashSetest simplement un ensemble qui n'autorise pas les éléments dupliqués et qui ne classe ni ne positionne ses éléments. Le code montre comment créer une collection de base et ajouter, supprimer et tester des éléments. Comme Vectorprend désormais en charge l' Collectioninterface, vous pouvez également exécuter ce code sur un vecteur, que vous pouvez tester en modifiant la HashSetdéclaration et le constructeur en Vector.

import java.util.collections. *; public class CollectionTest {// Statics public static void main (String [] args) {System.out.println ("Collection Test"); // Créer une collection HashSet collection = new HashSet (); // Ajout de la chaîne dog1 = "Max", dog2 = "Bailey", dog3 = "Harriet"; collection.add (chien1); collection.add (chien2); collection.add (chien3); // Dimensionnement System.out.println ("Collection créée" + ", size =" + collection.size () + ", isEmpty =" + collection.isEmpty ()); // Containment System.out.println ("La collection contient" + chien3 + ":" + collection.contains (chien3)); // Itération. Iterator prend en charge hasNext, ensuite, supprimez System.out.println ("Itération de collection (non triée):"); Itérateur itérateur = collection.iterator (); while (itérateur.hasNext ()) System.out.println ("" + iterator.next ()); // Suppression de collection.remove (dog1); collection.clear (); }}

Tirons maintenant parti de nos connaissances de base des collections et examinons d'autres interfaces et implémentations dans Java Collections Framework.

Bonnes implémentations concrètes

Nous avons exercé l' Collectioninterface sur une collection concrète, le HashSet. Regardons maintenant l'ensemble complet d'implémentations de collections concrètes fournies dans le framework Java Collections. (Reportez-vous à la section Ressources pour obtenir un lien vers la présentation annotée de Sun du framework Java Collections.)

Implémentations
Table de hachage Tableau redimensionnable Arbre équilibré (trié) Liste liée Héritage
Interfaces Ensemble HashSet * TreeSet * *
liste * Liste des tableaux * LinkedList Vecteur
Carte HashMap * TreeMap * Hashtable

Implementations marked with an asterix (*) make no sense or provide no compelling reason to implement. For instance, providing a List interface to a Hash Table makes no sense because there is no notion of order in a Hash Table. Similarly, there is no Map interface for a Linked List because a list has no notion of table lookup.

Let's now exercise the List interface by operating on concrete implementations that implement the List interface, the ArrayList, and the LinkedList. The code below is similar to the previous example, but it performs many List operations.

import java.util.collections.*; public class ListTest { // Statics public static void main( String [] args ) { System.out.println( "List Test" ); // Create a collection ArrayList list = new ArrayList(); // Adding String [] toys = { "Shoe", "Ball", "Frisbee" }; list.addAll( Arrays.toList( toys ) ); // Sizing System.out.println( "List created" + ", size=" + list.size() + ", isEmpty=" + list.isEmpty() ); // Iteration using indexes. System.out.println( "List iteration (unsorted):" ); for ( int i = 0; i < list.size(); i++ ) System.out.println( " " + list.get( i ) ); // Reverse Iteration using ListIterator System.out.println( "List iteration (reverse):" ); ListIterator iterator = list.listIterator( list.size() ); while ( iterator.hasPrevious() ) System.out.println( " " + iterator.previous() ); // Removing list.remove( 0 ); list.clear(); } } 

As with the first example, it's simple to swap out one implementation for another. You can use a LinkedList instead of an ArrayList simply by changing the line with the ArrayList constructor. Similarly, you can use a Vector, which now supports the List interface.

When deciding between these two implementations, you should consider whether the list is volatile (grows and shrinks often) and whether access is random or ordered. My own tests have shown that the ArrayList generally outperforms the LinkedList and the new Vector.

Notice how we add elements to the list: we use the addAll method and the static method Arrays.toList. This static method is one of the most useful utility methods in the Collections framework because it allows any array to be viewed as a List. Now an array may be used anywhere a Collection is needed.

Notice that I iterate through the list via an indexed accessor, get, and the ListIterator class. In addition to reverse iteration, the ListIterator class allows you to add, remove, and set any element in the list at the point addressed by the ListIterator. This approach is quite useful for filtering or updating a list on an element-by-element basis.

La dernière interface de base de Java Collections Framework est le Map. Cette interface est implémentée avec deux nouvelles implémentations concrètes, le TreeMapet le HashMap. Il TreeMaps'agit d'une implémentation d'arborescence équilibrée qui trie les éléments par clé.

Illustrons l'utilisation de l' Mapinterface avec un exemple simple qui montre comment ajouter, interroger et effacer une collection. Cet exemple, qui utilise la HashMapclasse, n'est pas très différent de la façon dont nous avons utilisé Hashtableavant les débuts du framework Collections. Désormais, avec la mise Hashtableà jour de pour prendre en charge l' Mapinterface, vous pouvez échanger la ligne qui instancie le HashMapet la remplacer par une instanciation du Hashtable.