Inizia con Java Collections Framework

JDK 1.2 introduce un nuovo framework per le raccolte di oggetti, chiamato Java Collections Framework. "Oh no," gemi, "non un'altra API, non un altro framework da imparare!" Ma aspetta, prima di voltarti, ascoltami: il framework delle collezioni vale il tuo impegno e gioverà alla tua programmazione in molti modi. Vengono subito in mente tre grandi vantaggi:

  • Aumenta notevolmente la leggibilità delle tue raccolte fornendo un set standard di interfacce che possono essere utilizzate da molti programmatori in molte applicazioni.
  • Rende il tuo codice più flessibile permettendoti di passare e restituire interfacce invece di classi concrete, generalizzando il tuo codice piuttosto che bloccarlo.
  • Offre molte implementazioni specifiche delle interfacce, consentendo di scegliere la collezione più adatta e offre le massime prestazioni per le proprie esigenze.

E questo è solo l'inizio.

Il nostro tour del framework inizierà con una panoramica dei vantaggi che offre per l'archiviazione di set di oggetti. Come scoprirai presto, poiché i tuoi vecchi amici cavalli di battaglia Hashtablee Vectorsupportano la nuova API, i tuoi programmi saranno uniformi e concisi - qualcosa per cui tu e gli sviluppatori che accedono al tuo codice apprezzerete sicuramente.

Dopo la nostra discussione preliminare, approfondiremo i dettagli.

Il vantaggio delle collezioni Java: una panoramica

Prima che Collections facesse il suo debutto più gradito, i metodi standard per raggruppare gli oggetti Java erano tramite l'array, il Vectore il Hashtable. Tutti e tre questi insiemi hanno metodi e la sintassi per accedere ai membri differenti: array utilizzano i simboli parentesi quadra ([]), Vectorutilizza il elementAtmetodo e Hashtablegli usi gete putmetodi. Queste differenze hanno portato a lungo i programmatori lungo il percorso verso l'incoerenza nell'implementazione delle proprie raccolte: alcuni emulano i Vectormetodi di accesso e altri emulano l' Enumerationinterfaccia.

Per complicare ulteriormente le cose, la maggior parte dei Vectormetodi sono contrassegnati come definitivi; ovvero, non è possibile estendere la Vectorclasse per implementare un tipo simile di raccolta. Potremmo creare una classe di raccolta che assomiglia a a Vectore si comporta come a Vector, ma non può essere passata a un metodo che accetta a Vectorcome parametro.

Infine, nessuna delle raccolte (array Vectoro Hashtable) implementa un'interfaccia di accesso ai membri standard. Quando i programmatori svilupparono algoritmi (come gli ordinamenti) per manipolare le collezioni, scoppiò un acceso discorso su quale oggetto passare all'algoritmo. Dovresti passare un array o un Vector? Dovresti implementare entrambe le interfacce? Parla di duplicazione e confusione.

Per fortuna, il Java Collections Framework risolve questi problemi e offre una serie di vantaggi rispetto all'utilizzo di nessun framework o all'utilizzo di Vectore Hashtable:

  • Un insieme utilizzabile di interfacce di raccolta

    Implementando una delle interfacce di base - Collection, Set, List, o Map- a garantire la sua classe è conforme a un'API comune e diventa più regolare e di facile comprensione. Quindi, sia che tu stia implementando un database SQL, un abbinatore di campioni di colore o un'applicazione di chat remota, se implementi l' Collectioninterfaccia, le operazioni sulla tua raccolta di oggetti sono ben note ai tuoi utenti. Le interfacce standard semplificano anche il passaggio e la restituzione di raccolte ae da metodi di classe e consentono ai metodi di lavorare su una più ampia varietà di raccolte.

  • Un set di base di implementazioni della raccolta

    Oltre alle fidate Hashtablee Vector, che sono state aggiornate per implementare le Collectioninterfacce, sono state aggiunte nuove implementazioni della raccolta, tra cui HashSete TreeSet, ArrayListe LinkedList, e HashMape Map. L'utilizzo di un'implementazione comune esistente rende il download del codice più breve e veloce. Inoltre, l'utilizzo del codice core Java esistente garantisce che qualsiasi miglioramento al codice di base migliorerà anche le prestazioni del codice.

  • Altri utili miglioramenti

    Ogni raccolta ora restituisce un Iterator, un tipo migliorato di Enumerationche consente operazioni sugli elementi come l'inserimento e l'eliminazione. Il Iteratorè "fail-fast", che significa che si ottiene un'eccezione se la lista si è iterazione viene modificato da un altro utente. Inoltre, raccolte basate su elenchi come Vectorreturn a ListIteratorche consentono l'iterazione e l'aggiornamento bidirezionali.

    Diverse raccolte ( TreeSete TreeMap) supportano implicitamente l'ordinamento. Usa queste classi per mantenere un elenco ordinato senza alcuno sforzo. Puoi trovare gli elementi più piccoli e più grandi o eseguire una ricerca binaria per migliorare le prestazioni di elenchi di grandi dimensioni. È possibile ordinare altre raccolte fornendo un metodo di confronto di raccolte (un Comparatoroggetto) o un metodo di confronto di oggetti (l' Comparableinterfaccia).

    Infine, una classe statica Collectionsfornisce versioni non modificabili (di sola lettura) e sincronizzate delle raccolte esistenti. Le classi non modificabili sono utili per impedire modifiche indesiderate a una raccolta. La versione sincronizzata di una raccolta è una necessità per i programmi multithread.

Il Java Collections Framework fa parte di Core Java ed è contenuto nel java.util.collectionspacchetto di JDK 1.2. Il framework è disponibile anche come pacchetto per JDK 1.1 (vedi Risorse).

Nota: viene denominata la versione JDK 1.1 delle raccolte com.sun.java.util.collections. Tieni presente che il codice sviluppato con la versione 1.1 deve essere aggiornato e ricompilato per la versione 1.2 e qualsiasi oggetto serializzato in 1.1 non può essere deserializzato in 1.2.

Esaminiamo ora più da vicino questi vantaggi esercitando il Java Collections Framework con del nostro codice.

Una buona API

Il primo vantaggio di Java Collections Framework è un'API coerente e regolare. L'API è codificata in un set di base di interfacce, Collection, Set, List, o Map. L' Collectioninterfaccia contiene operazioni di raccolta di base come l'aggiunta, la rimozione e i test per l'appartenenza (contenimento). Qualsiasi implementazione di una raccolta, sia essa fornita da Java Collections Framework o una delle tue creazioni, supporterà una di queste interfacce. Poiché il framework delle collezioni è regolare e coerente, imparerai gran parte dei framework semplicemente imparando queste interfacce.

Entrambi Sete Listimplementare l' Collectioninterfaccia. L' Setinterfaccia è identica Collectionall'interfaccia tranne che per un metodo aggiuntivo toArray, che converte a Setin un Objectarray. L' Listinterfaccia implementa anche l' Collectioninterfaccia, ma fornisce molte funzioni di accesso che utilizzano un indice intero nell'elenco. Ad esempio, get, removee settutti prendere un numero intero che colpisce l'elemento indicizzato nell'elenco. L' Mapinterfaccia non è derivata dalla raccolta, ma fornisce un'interfaccia simile ai metodi in java.util.Hashtable. Le chiavi vengono utilizzate per inserire e ottenere valori. Ciascuna di queste interfacce è descritta nei seguenti esempi di codice.

Il segmento di codice seguente mostra come eseguire molte Collectionoperazioni su HashSetuna raccolta di base che implementa l' Setinterfaccia. A HashSetè semplicemente un insieme che non consente elementi duplicati e non ordina o posiziona i suoi elementi. Il codice mostra come creare una raccolta di base e aggiungere, rimuovere e testare gli elementi. Poiché Vectorora supporta l' Collectioninterfaccia, puoi anche eseguire questo codice su un vettore, che puoi testare cambiando la HashSetdichiarazione e il costruttore in un file Vector.

import java.util.collections. *; public class CollectionTest {// Statics public static void main (String [] args) {System.out.println ("Collection Test"); // Crea una raccolta HashSet collection = new HashSet (); // Aggiunta della stringa dog1 = "Max", dog2 = "Bailey", dog3 = "Harriet"; collection.add (dog1); collection.add (dog2); collection.add (dog3); // Dimensionamento System.out.println ("Collection created" + ", size =" + collection.size () + ", isEmpty =" + collection.isEmpty ()); // Contenimento System.out.println ("Collection contains" + dog3 + ":" + collection.contains (dog3)); // Iterazione. Iterator supporta hasNext, next, remove System.out.println ("Collection iteration (unsorted):"); Iterator iterator = collection.iterator (); while (iteratore.hasNext ()) System.out.println ("" + iterator.next ()); // Rimozione di collection.remove (dog1); collection.clear (); }}

Costruiamo ora la nostra conoscenza di base delle raccolte e guardiamo altre interfacce e implementazioni in Java Collections Framework.

Buone implementazioni concrete

Abbiamo esercitato l' Collectioninterfaccia su una raccolta concreta, il HashSet. Diamo ora un'occhiata al set completo di implementazioni di raccolte concrete fornite nel framework Java Collections. (Vedere la sezione Risorse per un collegamento alla struttura annotata di Sun del framework Java Collections.)

Implementazioni
Tabella hash Array ridimensionabile Albero bilanciato (ordinato) Lista collegata Legacy
Interfacce Impostato HashSet * TreeSet * *
Elenco * Lista di array * Lista collegata Vettore
Carta geografica 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.

L'ultima interfaccia di base in Java Collections Framework è Map. Questa interfaccia è implementata con due nuove implementazioni concrete, il TreeMape il HashMap. È TreeMapun'implementazione ad albero bilanciata che ordina gli elementi in base alla chiave.

Illustriamo l'uso Mapdell'interfaccia con un semplice esempio che mostra come aggiungere, interrogare e cancellare una raccolta. Questo esempio, che utilizza la HashMapclasse, non è molto diverso da come abbiamo usato Hashtableprima del debutto del framework delle collezioni. Ora, con l'aggiornamento di Hashtableper supportare l' Mapinterfaccia, è possibile sostituire la riga che istanzia HashMape sostituirla con un'istanza di Hashtable.