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 Hashtable
et Vector
prennent 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 Vector
et 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 ([]), Vector
utilisent la elementAt
méthode, et Hashtable
utilisent get
et put
mé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 Vector
méthodes d'accès et d'autres émulent l' Enumeration
interface.
Pour compliquer davantage les choses, la plupart des Vector
méthodes sont marquées comme définitives; autrement dit, vous ne pouvez pas étendre la Vector
classe pour implémenter un type de collection similaire. Nous pourrions créer une classe de collection qui ressemblait à a Vector
et agissait comme a Vector
, mais elle ne pouvait pas être transmise à une méthode qui prend a Vector
comme paramètre.
Enfin, aucune des collections (tableau Vector
ou 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 Vector
et Hashtable
:
Un ensemble d'interfaces de collecte utilisables
En mettant en œuvre l' une des interfaces de base -
Collection
,Set
,List
ouMap
- 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'Collection
interface, 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
Hashtable
etVector
, qui ont été mis à jour pour implémenter lesCollection
interfaces, de nouvelles implémentations de collection ont été ajoutées, notammentHashSet
etTreeSet
,ArrayList
etLinkedList
, etHashMap
etMap
. 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é deEnumeration
qui permet des opérations d'élément telles que l'insertion et la suppression. LeIterator
est "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 queVector
retournent unListIterator
qui permettent une itération et une mise à jour bidirectionnelles.Plusieurs collections (
TreeSet
etTreeMap
) 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 (unComparator
objet) ou une méthode de comparaison d'objets (l'Comparable
interface).Enfin, une classe statique
Collections
fournit 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.collections
package 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' Collection
interface 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 Set
et List
implémentent l' Collection
interface. L' Set
interface est identique à l' Collection
interface, à l'exception d'une méthode supplémentaire toArray
, qui convertit a Set
en Object
tableau. L' List
interface implémente également l' Collection
interface, mais fournit de nombreux accesseurs qui utilisent un index entier dans la liste. Par exemple, get
, remove
et set
prendre tout un entier qui affecte l'élément indexé dans la liste. L' Map
interface 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 Collection
opérations sur HashSet
, une collection de base qui implémente l' Set
interface. A HashSet
est 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 Vector
prend désormais en charge l' Collection
interface, vous pouvez également exécuter ce code sur un vecteur, que vous pouvez tester en modifiant la HashSet
dé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' Collection
interface 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 TreeMap
et le HashMap
. Il TreeMap
s'agit d'une implémentation d'arborescence équilibrée qui trie les éléments par clé.
Illustrons l'utilisation de l' Map
interface avec un exemple simple qui montre comment ajouter, interroger et effacer une collection. Cet exemple, qui utilise la HashMap
classe, n'est pas très différent de la façon dont nous avons utilisé Hashtable
avant les débuts du framework Collections. Désormais, avec la mise Hashtable
à jour de pour prendre en charge l' Map
interface, vous pouvez échanger la ligne qui instancie le HashMap
et la remplacer par une instanciation du Hashtable
.