Sei sulla pagina 1di 3

Collezioni omogenee

di: Michele Arpaia


pubblicato il: 27-02-2003

Introduzione
Sin da principio la piattaforma Java ha reso disponibile varie classi container per collezionare oggetti. Dalla
versione 1.2 sono state introdotte, nel package java.util, una serie di classi ed interfacce che offrono una
elevata flessibilità nel gestire collezioni, implementando gli iteratori. Essendo contenitori parametrici,
gestiscono oggetti generici, ovvero oggetti istanza della classe Object. Il limite (oltre ad un obbligatorio cast)
è che le collezioni risultanti, se non opportunamente gestite, possono contenere oggetti di natura diversa.
Ad esempio, un Vector di oggetti Impiegati può contenere anche oggetti di tipo String, che in quel vettore
non trovano una naturale giustificazione. In questo articolo presenteremo due idiomi che affrontano il
problema da due punti di vista nonché un confronto che evidenzi i contesti dove è più opportuno utilizzare
uno piuttosto che l’altro.

Prima soluzione: checking statico


Consideriamo di voler gestire un insieme di Impiegati di un’ azienda informatica. Tralasciando ogni
considerazione sulla scelta del modello adottato - sul quale ci sarebbe molto da (ri)dire - ci basti sapere che
esiste una classe astratta Employee e varie sottoclassi, come Engineer, Manager, Secretary. Il nostro
compito è quello di fare in modo che la nostra collezione contenga solo impiegati e nient’ altro (liberiamoci
pure dall’ onere di scegliere la migliore struttura dati, diciamo che ci è stato imposto di usare una
LinkedList).
Solitamente la prima idea che viene in mente è quella di estendere LinkedList. Questo comporta una serie
di svantaggi (mostrando tra l’ altro un cattivo uso dell’
ereditarietà) tra i quali il peggiore è il seguente: siamo
costretti a ridefinire dei metodi wrapper per ogni metodo che considera Object come parametro di input o di
output (per evitare di aggiungere elementi incompatibili).
Un primo approccio è adottare la delegation. Consideriamo il seguente listato:

Li
st
ato1–Ge
sti
onet
ypes
afediunac
oll
ezi
onidiogge
ttiEmpl
oye
e
import java.util.*;
public class ManagingEmployee {
private AbstractList employees = new LinkedList();

public void addEmployee(Employee emp) // type safe {


employees.add(emp);
}
public Employee getEmployee(int index) {
return (Employee)employees.get(index);
}
public void removeEmployee(Employee emp) {
employees.remove(emp);
}


}

Come è facile vedere, i metodi della classe ManagingEmployee espongono dei comportamenti che
gestiscono il tipo di classe (nel nostro caso Employee) da caricare nella struttura dati scelta. In questo
modo si popola la collezione solo con il tipo di dato opportuno (naturalmente ogni sottoclasse di Employee è
compatibile con la nostra collection) e quello che è importante è che il compilatore farà tutto il lavoro per noi
garantendo un type safe a run-time.

Seconda soluzione: checking dinamico

1 di 3
Un approccio alternativo (che ha i suoi vantaggi come vedremo tra poco) è quello di rimandare a run-time il
check del tipo di dato da inserire nella collection. Questo trova la sua giustificazione quando il focus è più
sulla riusabilità che sul type-safe. L’
idea di fondo è quello di utilizzare l’
RTTI di Java.

Li
st
ato2–Col
lez
ionege
ner
icac
onl
atec
hec
kingde
iti
pi
import java.util.*;
public class RTCollection {
private Class class_;
private AbstractList elements = new LinkedList();

public RTCollection(Class class_) {


this.class_=class_;
}

public void add (Object obj) throws WrongClassException {


Class c = obj.getClass();
if(class_.isAssignableFrom(c)==false)
throw new WrongClassException(""+c); // classe che estende Exception
elements.add(obj);
}

public Object get(int index) {


return elements.get(index);
}

public void remove(Object obj) {


elements.remove(obj);
}


}

Il seguente frammento di codice client della classe ne mostra l’


utilizzo:


RTCollection employee = new RTCollection(Employee.class);
try {
employee.add(new Manager(…)); // okay
employee.add(“Employee”); // lancerà l’eccezione
}
catch (WrongClass Exception wce) {
wce.printStackTrace();
}

Da notare l’
uso del metodo isAssignableFrom() in luogo di un semplice controllo di uguaglianza (c!=class). Il
perché è presto detto: il controllo c!=class equivarrebbe, nel caso di Employee, a
Manager.class!=Employee.class, che restituirebbe true facendo scattare l’ eccezione. Il metodo
isAssignableFrom() della classe Class (introdotto a partire dalla versione 1.1) controlla se la classe passata
come parametro è una sottoclasse di un'altra (mediante i metodi Class.getSuperClass() e
Class.getInterfaces()), quindi rispondendo proprio al nostro requisito.

Confronto
Di seguito un breve riepilogo del confronto tra i due paradigmi:

Paradigma Benefici Svantaggi

Compile Il checking statico Il numero di classi da


typesafe assicura performance sviluppare tende a
collection type safe. crescere poiché per ogni
tipo andrebbe costruita
una collection ad-hoc.

Runtime - Riusabilità. - Rischio di eccezioni a


typed - Non impatta sul runtime.
collection numero di classi totali - Abbassamento delle

2 di 3
poiché un contenitore performance
generico si “
specializza” specialmente
a runtime. nell’
aggiungere nuovi
elementi alla collection.

Conclusioni
Su Javaworld (vedi riferimenti) è stato pubblicato un piccolo toolkit che consente di specializzare a runtime il
tipo di ogni collezione presente nelle API Java (Map, Collection, Set, eccetera).
Nella pratica generalmente è preferibile utilizzare le collezioni con checking statico, ma se gli obiettivi sono
la costruzione di un framework o comunque di un codice flessibile e riusabile a scapito delle performance e
dei rischi di exception a runtime, allora lì è utile prendere in considerazione il paradigma Runtime typed.
Una piccola nota: naturalmente i code snippet mostrati sono molto poveri per meglio sottolineare le
tecniche di checking. Ad esempio andrebbero previsti degli iteratori o alternativamente un criterio “ read
only”per leggere gli elementi della collection, ma questo è un altro discorso.

Riferimenti
(1) Dr. Piet Jonas, "Secure type-safe collections", presso
http://www.javaworld.com/javaworld/jw-04-2001/jw-0427-collections_p.html
(http://www.javaworld.com/javaworld/jw-04-2001/jw-0427-collections_p.html)

3 di 3