Le collezioni di oggetti
Prof. Accarino
IIS Altiero Spinelli via Leopardi 132
Sesto San Giovanni
Contenitori di oggetti

Java mette a disposizione una libreria per
gestire gruppi di oggetti organizzandola in due
tipologie:



Collection: una raccolta sequenziale di singoli
elementi ai quali sono applicate una o più regole (List,
Set, Queue)
Map: un gruppo di coppie chiave-valore indicanti
oggetti, permettendo di recuperare un valore mediante
la chiave ad esso associata
La distinzione si basa sul numero degli elementi
contenuti in ciascuna posizione del contenitore
Collection




Una Collection è un oggetto che raggruppa elementi
multipli in una singola unità
Viene utilizzata per memorizzare, recuperare e
manipolare dati, per trasmetterli da un metodo ad un
altro
Tipicamente rappresentano dati correlati tra loro, come
una collezione di numeri telefonici, collezione di lettere,
etc.
Sono state introdotte a partire dalla release 1.2
(collection framework)
Collection Framework

Il framework dei contenitori è composto da:

Interfacce:




Implementazioni:



Tipi di dato astratti che rappresentano le classi contenitori
Permettono di manipolare i contenitori indipendentemente dai dettagli della
rappresentazione
In genere formano una gerarchia
Implementazioni concrete delle interfacce
Sono le strutture dati riusabili
Algoritmi



Metodi che effettuano delle computazioni sui contenitori, come ad esempio
ordinamento, ricerca, …
Gli algoritmi sono polimorfici poiché gli stessi metodi possono essere applicati
a differenti implementazioni
Sono le funzionalità riusabili
Gerarchia di collection FrameWork
Interfacce

Set



List




Collezione che non può contenere duplicati
Astrazione dell’insieme matematico
Collezione ordinata (detta anche sequenza)
Può contenere elementi duplicati
Si accede agli elementi mediante un indice intero
(posizione)
Queue

Rappresenta una coda di elementi,l'approccio è rivolto a
risolvere problemi di sincronizzazione di programmi
concorrenti e il loro studio esula da questo contesto
Interfacce

SortedSet



Insieme dove gli elementi sono ordinati in ordine
ascendente
Operazioni aggiuntive per utilizzare l’ordinamento
Deque (double ended queue)

Coda che permette l’inserimento e la rimozione di
elementi sia in testa che in coda
Utilizzo di Collection non parametrizzate




Le collection in Java contengono oggetti di tipo Object e
E’ necessario effettuare un casting quando si recupera
l’oggetto
E’ possibile contenere tipi eterogenei
Non è possibile inserire valori di tipi primitivi
E’ necessario utilizzare tipi wrapper: Integer, Long ecc.
Esempio:
ArrayList al= new ArrayList();
al.add(“Pippo”);
al.add(new Integer(5));
String s=(String)al.get(0);
Integer numero = (Integer)dati.get(0);
int n = numero.intValue();

Svantaggi nell’utilizzo di liste non Parametrizzate
Uno svantaggio tipico è la perdita di informazione sul tipo
quando si inseriscono oggetti nel contenitore. Infatti:

poiché non vi sono restrizioni sul tipo di oggetti inseribili
nel contenitore, è possibile inserire senza problemi cani
in una collezione di gatti (fonte di potenziali errori)

a causa della perdita del tipo, occorre eseguire una
forzatura (cast) “corretta”, a run time, all’atto
dell’estrazione dell’oggetto per non incorrere in
un’eccezione
Esempio:
import java.util.*;
class Gatto {
public class CaniEGatti {
// costruttore
public Gatto(int i)
// restituisce l ’ identificativo unico
public static void main(String[] args)
{
List gatti = new ArrayList();
public int getID()
}
for(int i = 0; i < 7; i++)
gatti.add(new Gatto(i));
public class Cane {
gatti.add(new Cane(7));
// costruttore
/* Eccezione rilevata a run time */
public Cane(int i)
for(int i = 0; i < gatti.size(); i++)
((Gatto)gatti.get(i)).id();
// restituisce l ’ identificativo unico
public int getID()
}
}
}
Parametrizzare la lista
Per ovviare ai problemi precedenti è lecito definire una nuova classe lista
parametrizzata
List<Gatto> gatti = new ArrayList<Gatto>();
List<Cane> cani = new ArrayList<Cane>();
for (int i = 0; i < 7; i++) // aggiungi
gatti.add(new Gatto(i));
for (int i = 0; i < 3; i++) // aggiungi
cani.add(new Cane(i));
Vantaggi nell’uso di generici
I principali vantaggi dovuti all’introduzione dei tipi
generici sono:

Il compilatore può verificare qualsiasi
operazione add di oggetti alla collezione

il tipo dell’oggetto estratto da una collezione è
noto, quindi non vi è la necessità di operare un
cast a un tipo diverso (fonte di potenziali errori
se il cast è fatto su tipi non omologhi)
Implementazioni di Vettori
Le classi java.util.Vector e java.util.ArrayList definiscono degli oggetti, chiamati
vettori, che consentono di rappresentare sequenze di oggetti di lunghezza
variabile.
Ciascun oggetto in un vettore ha un numero intero, detto indice, che ne indica la
posizione nel vettore. Grazie all'indice è possibile accedere indipendentemente a
ciascun elemento della sequenza. L'accesso ad una posizione inesistente provoca
un errore (viene lanciata un'eccezione).
Al momento della dichiarazione o creazione di un vettore, il tipo base degli
elementi del vettore va indicato tra parentesi angolate dopo il nome della classe
(Vector e ArrayList sono classi generiche). Ad esempio, per costruire un vettore
di stringhe (inizialmente vuoto) e assegnarlo alla variabile vet, scriveremo:
ArrayList<String> vet = new ArrayList<String>();
Implementazioni di Vettori
I vettori sono dunque simili agli array.
Le differenze principali sono due:
 la dimensione di un vettore può variare durante l'esecuzione di un
programma;
,
, ...
 il tipo base di un vettore NON può essere un tipo primitivo (int double
).
L'implementazione dei vettori è basata sugli array. Al momento della
creazione di un vettore, alla variabile di istanza elementData viene assegnato
un array di oggetti la cui dimensione dipende dal costruttore utilizzato:
String[ ] elementData = new String[initialCapacity];
Successivamente, se la capacità dell’array non è più sufficiente, viene creato
un nuovo array più grande nel quale vengono copiati tutti gli elementi del
vecchio.
Realizzazione in memoria di Vettori
Differenze tra Vector e ArrayList
Nel seguito, usando la sintassi Java 6.0, indicheremo con Vector<E> e ArrayList<E> le
classi generiche che definiscono i vettori quando il tipo base non è specificato. Si noti
che <E> può essere considerata una variabile di tipo, che può essere istanziata con
qualunque classe Java.
Le classi generiche Vector<E> e ArrayList<E> sono sostanzialmente equivalenti, ma:
 I metodi di Vector<E> sono sincronizzati, mentre quelli di ArrayList<E> non lo
sono. Quindi se il programma èconcorrente (cioè usa il multi-threading di Java) è
opportuno usare Vector<E>, altrimenti conviene sempre ArrayList<E> perchè più
efficiente.
 Vector<E> fornisce, con opportuni metodi e costruttori, un controllo maggiore sulla
capacità, cioè la dimensione dell'array soggiacente.
 Per motivi storici, Vector<E> fornisce più metodi con nomi diversi per manipolare
gli elementi di un vettore.
•In genere conviene abituarsi ad usare sempre la classe ArrayList
Classi Vector<E> e ArrayList<E>: costruttori
I costruttori di Vector<E> permettono di specificare la capacità iniziale del vettore
(initialCapacity) e il valore da usare per aumentarela capacità (capacityIncrement)
quando necessario. Se (capacityIncrement == 0), il nuovo array avrà capacità doppia
rispetto all'attuale.
/* crea un vettore vuoto, con i parametri specificati */
Vector (int initialCapacity, int capacityIncrement)
/* per default, capacityIncrement=0 */
Vector (int initialCapacity)
/* per default, initialCapacity = 10 e capacityIncrement = 0 */
Vector ()
I costruttori di ArrayList<E> permettono di specificare solo la capacità iniziale del
vettore.
/* crea un vettore con la capacita' iniziale indicata */
ArrayList (int initialCapacity)
/* crea un vettore vuoto; la capacita' iniziale non e' specificata */
ArrayList ()
Come usare i Vettori
Si usa
preferibilmente quando
un array
•I dati sono tipi elementari;
•La lunghezza dell'array è nota al momento della creazione;
•La lunghezza dell'array non varia dinamicamente.
ArrayList
•I dati non sono tipi elementari o si usa un tipo involucro;
•La lunghezza non è nota al momento della creazione;
•La lunghezza varia dinamicamente;
Vector
Solo per compatibilità con programmi vecchi.
Principali metodi di ArrayList

boolean add(Object element)


void add(int index, Object element)


Rimuove tutti gli elementi dalla lista.
Iterator iterator()


Sostituisce l’elemento dell’indice specificato con
l’elemento specificato.
void clear()


Ritorna l’elemento della lista dell’indice
specificato.
Object set(int index, Object element)


Inserisce l’elememnto nella posizione specificata
dall’indice.
Object get(int index)


Aggiunge l’elemento alla fine della lista.
Ritorna un Iteratore per scorrere gli elementi in
sequenza.
int size()

Ritorna il numero degli elementi della lista.
Iterator

Modo “universale” per scorrere collezioni di elementi,
indipendentemente dalla particolare disposizione degli
elementi


Il metodo Iterator iterator() è disponibile in
tutte le classi che estendono la Collection
Iterator

boolean hasNext()


Object next()


Ritorna true se l’iterazione contiene ulteriori elementi.
Ritorna il prossimo elemento dell’iterazione.
void remove()

Rimuove dalla collezione l’ultimo elemento iterato
(optional operation).
Come funziona un Iteratore
Esercizio
Scrivere un metodo java
int somma(ArrayList a)
che somma gli elementi del vettore di interi utilizzando gli
iteratori.
5
3
4
8
2

Somma: 22
Ciclo di scorrimento:




Si ricava l’iteratore dall’ArrayList
Si utilizza un ciclo while che utilizza come condizione
Il metodo hasNext() dell’iteratore per continuare a ciclare,
Si usa next() per avere l’elemento corrente
Esempio
public static int somma(ArrayList a){
int somma=0;
Iterator i=a.iterator();
while (i.hasNext()){
Integer val=(Integer)i.next();
somma=somma+val.intValue();
}
return somma;
}
Il costrutto foreach in java
Il foreach è un particolare costrutto (disponibile a partire da Java 5)
che ci permette di iterare velocemente una struttura dati.
In java possiamo usarlo sia su un array oppure su oggetti di
tipo Iterable, cioè che dispongono di un iteratore (java.util.Iterator).
Le Collections di java (Linkedlist, ArrayList, etc.) sono tutti oggetti
di tipo Iterable.
il costrutto generico è il seguente :
for(type var : array)
{
//ciclo
}
Esempio somma elementi ciclo for e forech
Ciclo For
Ciclo Forech
public static int somma(int [] array) {
int somma = 0;
for(int i = 0; i < array.length; i++) {
somma += array[i];
}
return somma;
}
public static int somma(int [] array) {
int somma = 0;
for(int element:array)
somma+=element;
return somma;
}
Iterazione di un ArrayList
ArrayList <String> lista = new ArrayList<String>();
lista.add("a");
lista.add("b");
....
Iterator
Ciclo Forech
Iterator <String> it = lista.iterator();
while(it.hasNext()) {
String str = it.next();
...
}
for(String str:lista) {
.....
}
LinkedList
Rappresenta una lista di oggetti doppiamente concatenata in cui ogni nodo punta
sia al suo predecessore che al suo successore
Principali metodi di LinkedList
Creare una pila con LinkedList
public class Pila
{
private LinkedList list;
public Pila() { list=new LinkedList(); }
public void push(Object o) { list.addFirst(o); }
public Object pop() { return list.removeFirst(); }
public int size() { return list.size();}
}
Creare una coda con LinkedList
public class Coda
{
private LinkedList list;
public Coda() { list=new LinkedList(); }
public void push(Object o) { list.addLast(o); }
public Object pop() { return list.removeFirst(); }
public int size() { return list.size();}
}
la classe Stack<E>
In Java la classe Stack estende Vector, implementando
direttamente i metodi:
•empty() Controllo se la pila è vuota oppure no
•peek() Lettura dell'elemento in cima alla pila, senza eliminarlo
•pop() Estrazione dell'elemento in cima alla pila
•push(E item) Inserimento di un elemento in cima alla pila
ed eredita da Vector (tra gli altri) il metodo clear().
Il fatto di estendere Vector permette di usare anche tutti i
suoi metodi, in particolare l'accesso diretto agli elementi,
(possibilità poco elegante ma spesso comoda).
la classe ArrayDeque<E>
In informatica, una deque (solitamente pronunciato come deck, è l'abbreviazione
di double-ended queue, cioè coda doppia) è una struttura dati astratta simile a una
lista, anche chiamata lista concatenata testa-coda in quanto gli elementi possono
essere aggiunti o rimossi solamente dalla testa o dalla coda.
La classe ArrayDeque implementa una coda a doppia entrata
I principali metodi sono
 addFirst(e) Inserisce e all’inizio del deque
 addLast(e) Inserisce e alla fine del deque
 removeFirst() Restituisce e rimuove il primo elemento del deque
 removeLast() Restituisce e rimuove l’ultimo elemento del deque
 getFirst() Restituisce il primo elemento del deque
 getLast() Restituisce l’ultimo elemento del deque
 size() Restituisce il numero di elementi del deque
 isEmpty() Restituisce true se il deque è vuoto e false altrimenti