ATTENZIONE: il nuovo sito di riferimento per questa guida e altre cose più
o meno interessanti è
il mio BLOG
Molto spesso si ha necessità di conservare degli oggetti in una struttura dati. La scelta migliore per semplicità e velocità è l'array, ma non sempre è applicabile.
La libreria java.util fornisce delle collezioni pronte all'uso, strutturate in una gerarchia che prevede tre interfacce principali - List, Set e Map - e varie implementazioni.
Un Set (insieme) è un contenitore che mantiene una sola copia dell'oggetto, mentre Map è un'associazione (funzione) chiave - valore.
Ecco un esempio di lista:
List capitali = new ArrayList();
capitali.add("Roma");
capitali.add("Parigi");
5 capitali.add("Londra");
System.out.println(capitali);
È opportuno usare le interfacce invece delle implementazioni (linea 1).
In linea 7 viene chiamato il metodo toString(), che fornisce una
rappresentazione del contenuto della lista.
Se si prova a fare lo stesso con un array si vede che toString()
non fornisce la stessa informazione; in questo caso si possono usare i metodi
statici toString(...) o deepToString(...)
della classe Arrays.
Una collezione contiene Object, quindi quando si recuperano gli oggetti è necessario il casting - continuando l'esempio precedente:
String it = (String) capitali.get(0);Java 1.5 ha introdotto generics e autoboxing, che permettono un uso più diretto e sicuro delle collezioni:
List<String> capitali = new ArrayList<String>();In questo modo
capitali non è più una lista di oggetti,
ma di stringhe, quindi il casting non serve.
L'autoboxing (e specularmente unboxing) invece consente di creare liste di tipi primitivi:
List<Integer> primi = new ArrayList<Integer>(); primi.add(2); // autoboxinge più in generale di usare un tipo primitivo quando viene richiesto un tipo wrapper (Integer, Float, ecc.) o Object o Number (superclassi).
Il modo standard di accedere agli elementi di una collezione è tramite un Iterator:
Iterator i = capitali.iterator(); while(i.hasNext()) System.out.println(i.next());In java 5 una collezione si può visitare molto più agevolmente con l'enhanced for, già visto in azione per gli array:
for(String c : capitali) System.out.println(c);
In conclusione di questo capitolo vediamo un semplice esempio di implementazione di pila generica - nel main() un esempio d'uso:
import java.util.*;
/** Pila generica.
* Usa la nuova (1.5) interfaccia Queue, implementata da LinkedList.
*/
public class Pila<T> // notare il "segnaposto" per il tipo
{
private LinkedList<T> pila;
/** Crea una pila vuota
*/
public Pila()
{
pila = new LinkedList<T>();
}
/** Mette un elemento in testa alla pila.
* @param el l'elemento da inserire.
*/
public void push(T el)
{
pila.addFirst(el);
}
/** Estrae un elemento dalla pila.
* @return L'elemento estratto.
* @throws NoSuchElementException se la pila e' vuota.
*/
public T pop()
{
return pila.remove(); // Queue, Java 1.5+
}
public String toString()
{
return pila.toString();
}
/** MAIN - per test */
public static void main(String... args)
{
// crea una pila vuota di Integer
Pila<Integer> p = new Pila<Integer>();
/* mette sulla pila 23, 0, -22
usa autoboxing, java 1.5 o superiore */
p.push(23);
p.push(0);
p.push(-22);
System.out.println(p);
System.out.println(p.pop());
System.out.println(p);
p.pop();
p.pop(); // ora la pila e' vuota!
System.out.println(p);
p.pop(); // lancia NoSuchElementException
}
}