6/3/2014 Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java Collection Framework Daniela Micucci [email protected] Introduzione • Una collezione – a volte chiamata container ‐ è un elemento “contenitore” di oggetti chiamati elementi • La necessità di strutture dati che raggruppino oggetti è comune a molte applicazioni – Ad esempio: • mail folder (collezione di mail) , • rubriche (collezione di associazioni nome‐numero di telefono) • ... Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 2 1 6/3/2014 Java Collection Framework • È un insieme di interfacce e di classi che supportano tre tipi di collezioni: – Insiemi • Collezioni di elementi che non ammettono duplicati – Liste • Collezioni ordinate di elementi • Chiamate anche sequenze – Mappe • Collezione di coppie <chiave, valore> – Il valore è quindi l’elemento – La chiave è usata per inserire l’elemento e per recuperare l’elemento • Le chiavi non ammettono duplicati • Le mappe sono anche chiamate dizionari Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 3 Java Collection Framework • Il Java Java Collection Framework contiene – Un insieme di interfacce (e classi astratte) che specificano un insieme di funzionalità – Un insieme vasto di collezioni già implementate che realizzano liste, insiemi e mappe – Diverse implementazioni per ciascuna tipologia di collezione • Le strutture dati sono contenitori generici per gli oggetti – Fino alla versione 1.4 si usava la classe Object – Dalla versione 1.5 è stato aggiunto il supporto ai generici Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 4 2 6/3/2014 Organizzazione • Liste e Insiemi: • Mappe: – implementano l’interface Collection<E> – implementano l’interface Map<K,V> «interface» Collection «interface» Set «interface» Map «interface» List AbstractCollection «interface» SortedMap «interface» SortedSet AbstractMap AbstractList AbstractSet AbstractSequentialList Set - Insiemi TreeSet Software Architecture Lab www.sal.disco.unimib.it List - Liste HashSet Vector ArrayList Map - Mappe LinkedList TreeMap HashMap Programmazione con Java: Collection Framework 5 L’interface Collection<E> • L’interfaccia Collection<E> specifica le operazioni di base che tutte le collezioni di elementi devono implementare (Liste e Insiemi) • Nonostante non sia espressamente richiesto dall’interfaccia, qualunque classe che implementi l’interfaccia Collection<E> dovrebbe avere almeno due costruttori: – Senza parametri e che crea un oggetto di tipo Collection<E> vuoto – Con un parametro di tipo Collection<? extends E> che crea un oggetto di tipo Collection<E> contenente gli stessi elementi dell’argomento Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 6 3 6/3/2014 L’interface Collection<E> Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 7 L’interface Collection<E> • I metodi opzionali devono comunque essere implementati – Possono deviare dalla semantica attribuita – Se deviano dalla semantica fornendo una implementazione triviale, devono generare una UnsupportedOperationException • Se, per qualche motivo, non si è interessati a definire un’implementazione vera e propria • Una UnsupportedOperationException è una RunTimeException e quindi non è necessario gestirla o dichiararla in una clausola throws Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 8 4 6/3/2014 Insiemi: l’interface Set<E> Insieme: collezione di elementi che non ammette duplicati • L’interface Set<E> definisce le operazioni che un insieme in quanto tale deve offrire • Per evitare che esistano duplicati all’interno della collezione, l’interface Set<E> cambia la semantica di alcuni metodi ereditati da Collection<E> – Due elementi e1 e e2 sono considerati duplicati e quindi non possono appartenere allo stesso set se e solo se e1.equals(e2) == true • Non ha bisogno di definire ulteriori operazioni Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 9 Insiemi: l’interface Set<E> Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 10 5 6/3/2014 Liste: l’interface List<E> Lista: collezione ordinata di elementi anche duplicati • L’interface List<E> definisce le operazioni che una lista in quanto tale deve offrire • L’interface List<E> cambia la semantica di alcuni metodi ereditati da Collection<E> • Aggiunge nuovi metodi in modo da poter gestire l’indicizzazione degli elementi (e quindi l’ordinamento) – Avere un accesso posizionale agli elementi • Tramite indice intero che parte da 0 – Ricercare un elemento e ottenere la sua posizione – Eseguire operazioni in un determinato intervallo di List Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 11 Liste: l’interface List<E> Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 12 6 6/3/2014 Liste: l’interface List<E> Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 13 Mappe: l’interface Map<K,V> Mappa: collezione di coppie <chiave, valore> con chiavi non duplicate • L’interface Map<K,V> definisce le operazioni che una mappa in quanto tale deve offrire • I metodi di aggiunta coppie devono verificare che la chiave della nuova coppia non sia già presente nella mappa – Ogni chiave può mappare al massimo un valore – Una chiave k1 è considerata duplicata se containsKeys(k1) restituisce true – Il che vuol dire che esiste una chiave k2 tale che k2.equals(k1) == true Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 14 7 6/3/2014 Mappe: l’interface Map<K,V> • Nonostante non sia espressamente richiesto dall’interfaccia, qualunque classe che implementi l’interfaccia Map<K,V> dovrebbe avere almeno due costruttori: – Senza parametri e che crea un oggetto di tipo Map<K,V> vuoto – Con un parametro di tipo Map<K,V> che crea un oggetto di tipo Map<K,V> contenente gli stessi elementi dell’argomento • Definisce almeno i metodi per – – – – Inserire elementi con chiave Recuperare/rimuovere gli elementi tramite chiave Verificare se una chiave è già presente Recuperare tutte le chiavi/valori Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 15 Mappe: l’interface Map<K,V> Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 16 8 6/3/2014 Collezioni ordinate • Le classi che implementano l’interface List implicitamente definiscono una sequenza ordinata di elementi • Map e Set sono collezioni non ordinate • Per avere un ordinamento anche su mappe e insiemi, occorre che le implementazioni concrete derivino rispettivamente da – SortedMap: è una Map che mantiene il collegamento chiave‐valore in ordine crescente di chiave – SortedSet : è un Set che mantiene gli elementi in ordine crescente Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 17 Interface SortedSet<E> • È un Set che mantiene gli elementi ordinati in ordine crescente • Gli insiemi ordinati sono utilizzati per realizzare insiemi naturalmente ordinati – Una lista di parole – Una lista di persone – … «interface» Collection «interface» Set «interface» SortedSet • Gli elementi sono ordinati – Secondo il loro ordine naturale o – Mediante un Comparator (in genere fornito in fase di instanziazione del set) Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework TreeSet 18 9 6/3/2014 Ordinamento naturale • L’ordinamento naturale, come dice la parola, è quello che uno si aspetta – Banane, mele, pere, … – 1, 5, 23 – 12/05/2012, 01/06/2012, … • Dal punto di vista implementativo, un insieme di oggetti possono essere ordinati naturalmente se la classe che li definisce implementa l’interface Comparable public interface Comparable<T> { public int compareTo(T o); } Programmazione con Java: Collection Framework Software Architecture Lab www.sal.disco.unimib.it 19 In metodo compareTo • Dati due oggetti o1 e o2 istanziati a partire da una classe che implementa l’interface Comparable o1.compareTo(o2) restituirà: 0 Se o1 e o2 sono ‘uguali’ Intero negativo Se o1 è più piccolo di o2 Intero positivo Se o1 è più grande di o2 Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 20 10 6/3/2014 Esempio public class DemoCompare { public static void main(String a[]){ String s1 = new String("a"); String s2 = new String("b"); System.out.println(s1.compareTo(s2)); System.out.println(s2.compareTo(s1)); s2 = new String("a"); System.out.println(s1.compareTo(s2)); } } Output: ‐1 1 0 • Stessi risultati per altre classi predefinite come Date e Integer Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 21 Esempio: classe personalizzata public class Persona implements Comparable<Persona> { private String cognome; private String nome; private String eMail; public Persona(String cognome, String nome, String eMail) { this.cognome = cognome; this.nome = nome; this.eMail = eMail; } @Override public int compareTo(Persona altra) { int val = cognome.compareTo(altra.cognome); if(val != 0) return val; else return nome.compareTo(altra.nome); } // … } • Classe completa Software Architecture Lab www.sal.disco.unimib.it Confronto solo su cognome e poi nome public class DemoComparable { public static void main(String a[]){ Persona p1 = new Persona("Rossi", "Mario", "[email protected]"); Persona p2 = new Persona("Rossi", "Marco", "[email protected]"); System.out.println(p1.compareTo(p2)); //stampa 6 System.out.println(p2.compareTo(p1)); //stampa -6 p2 = new Persona("Rossi", "Mario", "[email protected]"); System.out.println(p1.compareTo(p2)); //stampa 0 } } Programmazione con Java: Collection Framework 22 11 6/3/2014 Coerenza ordinamento naturale/equals • L’ordinamento naturale per una classe C è detto essere coerente con l’uguaglianza (equals) se e solo se e1.compareTo(e2) == 0 ha lo stesso valore booleano di e1.equals(e2) per ogni istanza e1 e e2 di C • È importante mantenere la coerenza poiché alcuni sorted set si comportano stranamente se non viene mantenuta la coerenza – Un sorted set non ammette duplicati in termini di equals – Si provi ad inserire in un sorted set due elementi a e b tali che (!a.equals(b) && a.compareTo(b) == 0) • Il secondo non viene inserito! Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 23 Esempio: classe personalizzata Confronto solo su cognome e poi nome • Classe completa Software Architecture Lab www.sal.disco.unimib.it public class Persona implements Comparable<Persona> { private String cognome; private String nome; private String eMail; // … @Override public boolean equals(Object obj) { // … Persona other = (Persona) obj; if (cognome == null) { if (other.cognome != null) return false; } else if (!cognome.equals(other.cognome)) return false; if (nome == null) { if (other.nome != null) return false; } else if (!nome.equals(other.nome)) return false; return true; } @Override public int compareTo(Persona altra) { int val = cognome.compareTo(altra.cognome); if(val != 0) return val; else return nome.compareTo(altra.nome); } // … } Programmazione con Java: Collection Framework 24 12 6/3/2014 Ordinamento mediante Comparator • Se si vuole specificare un ordinamento diverso da quello naturale, si realizza un Comparator: – Una interface che impone un ordinamento totale su una collezione di oggetti che è diverso da quello naturale public interface Comparator<T> { public int compare(T o1, T o2); //… } • Stesso comportamento del metodo compareTo • Lo specifico in fase di instaziazione della collezione ordinata – Esempio: TreeSet(Comparator<? super E> comparator) costruisce un nuovo set ordinato in accordo al comparator specificato Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 25 Ordinamento mediante Comparator • Se si vuole specificare un ordinamento diverso da quello naturale, si realizza un Comparator: – Una interface che impone un ordinamento totale su una collezione di oggetti che è diverso da quello naturale public interface Comparator<T> { public int compare(T o1, T o2); //… } • Stesso comportamento del metodo compareTo • Coerenza ordinamento/equals dovrebbe essere garantita • Lo specifico in fase di instaziazione della collezione ordinata – Esempio: TreeSet(Comparator<? super E> comparator) costruisce un nuovo set ordinato in accordo al comparator specificato Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 26 13 6/3/2014 Esempio Comparator • Classe che implementa Comparator per confrontare due persone import java.util.Comparator; public class ComparatorPersone implements Comparator<Persona> { @Override public int compare(Persona o1, Persona o2) { int val = o1.getCognome().compareTo(o2.getCognome()); if(val != 0) return val; else return o1.getNome().compareTo(o2.getNome()); } Confronto solo su cognome e poi nome } Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 27 Interface SortedSet<E> Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 28 14 6/3/2014 Interface SortedMap<K,V> • È una Map che mantiene le chiavi ordinate in ordine crescente «interface» Map – Analoga a SortedSet • Le mappe ordinate sono utilizzate per realizzare insiemi naturalmente ordinati di chiavi/valore – Un dizionario – Un elenco telefonico – … «interface» SortedMap • Come per l’interface SortedSet, le chiavi sono ordinate – Secondo il loro ordine naturale o – Mediante un Comparator (in genere fornito in fase di instanziazione della map) Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework TreeMap 29 Interface SortedMap<K,V> Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 30 15 6/3/2014 Implementazioni disponibili • I tipi di collezioni possono essere implementati in diverse maniere Implementazioni disponibili Interface Hash table Set HashSet List Map Software Architecture Lab www.sal.disco.unimib.it Array ridimensionabile Albero ordinato Liste concatenate TreeSet ArrayList HashMap LinkedList TreeMap Programmazione con Java: Collection Framework 31 Caratteristiche delle implementazioni • Le liste concatenate (o linked list) sono liste realizzate mediante puntatori • Gli array ridimensionabile (o resizable array) sono liste realizzate tramite array di reference • Gli alberi ordinati (o sorted tree ) sono alberi bilanciati ed ordinati realizzati mediante puntatori • Le tabelle di hash (o hash table) sono tabelle realizzate mediante delle funzioni hash – Vediamo le hash table cosa sono… Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 32 16 6/3/2014 Hashing • L'Hashing è la trasformazione di una stringa di caratteri in una sequenza di lunghezza fissa più breve denominata hash (o chiave) • Una funzione di hash mappa quindi una stringa di lunghezza arbitraria in una stringa di lunghezza predefinita Il gatto Funzione di hash DM040709 Il gatto mangia il topo Funzione di hash 04LM0709 Il gatto mangia il pesce Funzione di hash 1703DL08 • L'Hashing è utilizzato per indicizzare e recuperare gli elementi di un database – È più veloce trovare l’elemento mediante una chiave più corta piuttosto che il suo valore originale Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 33 Hash table • Una hash table o hash map è una struttura dati che usa una funzione di hash per mettere in corrispondenza una data chiave (per esempio il nome di una persona) con un dato valore (ad esempio il suo numero di telefono) • Di conseguenza, una hash table realizza un array associativo – La funzione di hash è utilizzata per trasformare la chiave nell’indice (l’hash) di un array di elementi dove il valore corrispondente alla chiave sarà ricercato chiavi funzione di hash indice (o hash) valori 00 Mario Rossi Giorgio Bianchi Piero Verdi 01 02‐1234567 02 02‐12495611 …. … 49 02‐34234567 50 Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 34 17 6/3/2014 Caratteristiche funzione di hash • Collisione – Due chiavi a cui viene calcolato lo stesso hash • Fattore di carico (load factor) – Calcolato come Celle libere/Elementi presenti – Quanta probabilità ha un nuovo elemento di collidere con uno già presente nella tabella – È bene dunque mantenere il load factor il più basso possibile (di solito un valore di 0.75 è quello ottimale) per ridurre al minimo il numero di collisioni Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 35 Implementazioni disponibili • Come detto, esistono disponibili diverse implementazioni delle collezioni • Ogni implementazione ha i suoi punti di forza o di debolezza rispetto alla struttura dati utilizzata • Quando si deve selezionare un’implementazione occorre appunto analizzarne proprio i pro/contro • … vediamone alcuni Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 36 18 6/3/2014 Set: esempi di implementazioni • TreeSet<E> «interface» Collection – Conviene se si ha necessità di mantenere un ordinamento tra gli elementi – L’implementazione è simile ad un albero binario, che viene tenuto bilanciato in fase di inserimento «interface» Set AbstractCollection «interface» SortedSet • HashSet<E> – Gli elementi sono memorizzati in ordine sparso, senza alcuna garanzia sull’ordine in cui potranno essere letti – È implementata usando una hash table – Conviene se si hanno prevalentemente accessi diretti agli elementi Software Architecture Lab www.sal.disco.unimib.it AbstractSet Set - Insiemi TreeSet HashSet Programmazione con Java: Collection Framework 37 Liste: esempi di implementazioni • ArrayList<E> – È l’implementazione più usata – Conviene se si hanno prevalentemente accessi posizionali agli elementi (diretti) «interface» Collection «interface» List • Vector<E> – La prima collezione definita nel linguaggio – Alternativa a ArrayList • LinkedList<E> – Lista linkata bidirezionale e permette di scorrere gli elementi partendo sia dall’inizio che dalla fine – Conviene se si hanno prevalentemente cancellazioni (veloce perché si cambiano solo i collegamenti fra nodi della lista – Accedere all’i‐esimo elemento è un’operazione lenta AbstractList AbstractSequentialList List - Liste Vector ArrayList LinkedList • infatti devono essere percorsi tutti gli elementi precedenti Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 38 19 6/3/2014 Mappe: implementazioni • HashMap<K,V> «interface» Map – conviene se si hanno accessi diretti agli elementi – tempo di accesso costante • TreeMap<K,V> «interface» SortedMap AbstractMap – conviene se si ha necessità di mantenere un ordinamento tra gli elementi – tempo di accesso logaritmico Map - Mappe TreeMap Software Architecture Lab www.sal.disco.unimib.it HashMap Programmazione con Java: Collection Framework 39 Tip #1 • Le classi contengono metodi che specificano di lanciare numerose eccezioni – Sono tutte comunque unchecked, utili per il debug • In classi implementate possono essere viste come run‐time error • Quando si codifica una collezione from scratch, occorre lanciare tutte le eccezioni che l’interfaccia implementata dichiara di lanciare Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 40 20 6/3/2014 ITERATORI Programmazione con Java: Collection Framework 41 L’interface Iterator • Un iteratore è un oggetto che permette di effettuare una visita degli elementi di una collezione (qualsiasi classe che implementa Collection) • Iterator è una interface così definita: public interface Iterator<E> { public boolean hasNext(); public E next(); public void remove(); //opzionale } – hasNaxt • restituisce true se esiste un elemento successivo – next • si posiziona sull’elemento successivo e lo restituisce – remove • rimuove l’elemento attuale Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 42 21 6/3/2014 L’interface Iterator • Si ottiene un iteratore di una collezione invocando il suo metodo iterator() che restituisce un oggetto di tipo Iterator – Hint: ogni volta che voglio iterare, devo farmi ridare l’iteratore • L’interface Map non espone il metodo iterator() • È possibile solo ottenere un iteratore per le chiavi e i valori – keySet() che restituisce un Set – values() che restituisce una Collection Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 43 Esempio di utilizzo import java.util.ArrayList; import java.util.Iterator; public class Demo01 { public static void main(String[] args) { ArrayList<String> lista = new ArrayList<String>(); lista.add("uno"); lista.add("due"); Iterator<String> i = lista.iterator(); while(i.hasNext()){ String el = i.next(); System.out.println(el); } i = lista.iterator(); i.next(); //rimuove l’ultimo elemento restituito da next i.remove(); System.out.println(lista); } } Output: uno due [due] Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 44 22 6/3/2014 Iterator per le liste: ListIterator • ListIterator estende Iterator e i metodi ereditati si comportano analogamente public interface ListIterator<E> extends Iterator<E>{ public boolean hasPrevious(); public E previous(); public int nextIndex(); public int previousIndex(); public void set(E e); //opzionale public void add(E e); //opzionale } • hasPrevious e previous sono analoghe a hasNext e next – – • Le prime si riferiscono all’elemento prima del cursore (implicito), le ultime all’elemento dopo il cursore previous muove il cursore all’indietro, next in avanti nextIndex restituisce l’indice dell’elemento che sarebbe restituito dall’invocazione della chiamata a next, perviousIndex ad una chiamata a previous Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 45 ESEMPI DI CLASSI Programmazione con Java: Collection Framework 46 23 6/3/2014 Interface List: Esempio ArrayList import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class DemoPersonaArrayList { public static void main(String a[]){ List<Persona> lista = new ArrayList<Persona>(); lista.add(new Persona("Micucci", "Daniela", "[email protected]")); lista.add(new Persona("Denaro", "Giovanni", "[email protected]")); lista.add(new Persona("Tisato", "Francesco", "[email protected]")); lista.add(new Persona("Sartori", "Fabio", "[email protected]")); } } Iterator<Persona> i = lista.iterator(); while(i.hasNext()){ Persona el = i.next(); System.out.println(el); } //Lo inserisce comunque in fondo anche se esiste gia' lista.add(new Persona("Sartori", "Fabio", "[email protected]")); System.out.println("Set nuovo: "); i = lista.iterator(); Output: while(i.hasNext()) Persona [cognome=Micucci, nome=Daniela] System.out.println(i.next()); Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Sartori, nome=Fabio] Set nuovo: Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Sartori, nome=Fabio] Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 47 Interface List: Esempio Vector import java.util.Vector; import java.util.Iterator; import java.util.List; public class DemoPersonaVector { public static void main(String a[]){ List<Persona> lista = new Vector<Persona>(); lista.add(new Persona("Micucci", "Daniela", "[email protected]")); lista.add(new Persona("Denaro", "Giovanni", "[email protected]")); lista.add(new Persona("Tisato", "Francesco", "[email protected]")); lista.add(new Persona("Sartori", "Fabio", "[email protected]")); } Iterator<Persona> i = lista.iterator(); while(i.hasNext()){ Persona el = i.next(); System.out.println(el); } //Lo inserisce comunque in fondo anche se esiste gia' lista.add(new Persona("Sartori", "Fabio", "[email protected]")); System.out.println("Set nuovo: "); i = lista.iterator(); Output: while(i.hasNext()) Persona [cognome=Micucci, nome=Daniela] System.out.println(i.next()); Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Sartori, nome=Fabio] Set nuovo: Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Sartori, nome=Fabio] Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 48 24 6/3/2014 Interface List: Esempio LinkedList import java.util.LinkedList; import java.util.ListIterator; import java.util.List; public class DemoPersonaTreeMap { public static void main(String a[]){ List<Persona> lista = new LinkedList<Persona>(); lista.add(new Persona("Micucci", "Daniela", "[email protected]")); lista.add(new Persona("Denaro", "Giovanni", "[email protected]")); lista.add(new Persona("Tisato", "Francesco", "[email protected]")); lista.add(new Persona("Sartori", "Fabio", "[email protected]")); } } ListIterator<Persona> i = lista.listIterator(); while(i.hasNext()){ Persona el = i.next(); System.out.println(i.next()); } //Non devo riavvolgere l'iteratore --> i = lista.listIterator(); System.out.println("Set all’indietro: "); while(i.hasPrevious()){ Persona el = i.previous(); Output: System.out.println(i.next()); Persona [cognome=Micucci, nome=Daniela] } Persona [cognome=Denaro, nome=Giovanni] //Lo inserisce comunque in fondo anche se esiste gia' Persona [cognome=Tisato, nome=Francesco] lista.add(new Persona( Persona [cognome=Sartori, nome=Fabio] "Sartori", "Fabio", "[email protected]")); Set all'indietro: Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Micucci, nome=Daniela] Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 49 Interface Set: Esempio TreeSet import java.util.TreeSet; import java.util.Iterator; import java.util.Set; public class DemoPersonaTreeSet { public static void main(String a[]){ Set<Persona> set = new TreeSet<Persona>(); set.add(new Persona("Micucci", "Daniela", "[email protected]")); set.add(new Persona("Denaro", "Giovanni", "[email protected]")); set.add(new Persona("Tisato", "Francesco", "[email protected]")); set.add(new Persona("Sartori", "Fabio", "[email protected]")); Iterator<Persona> i = set.iterator(); while(i.hasNext()) System.out.println(i.next()); Elementi ordinati Elementi duplicati non presenti //Anche se fosse un omonimo, non lo farebbe inserire: è un Set set.add(new Persona("Sartori", "Fabio", "[email protected]")); //Lo inserisce dopo Denaro set.add(new Persona("Fiamberti", "Francesco", "[email protected]")); System.out.println("Set nuovo: "); i = set.iterator(); while(i.hasNext()) System.out.println(i.next()); } } Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework Output: Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Tisato, nome=Francesco] Set nuovo: Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Fiamberti, nome=Francesco] Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Tisato, nome=Francesco] 50 25 6/3/2014 Interface Set: Esempio HashSet • HashSet utilizza una tabella di hash per memorizzare i suoi elementi • Indicizza (i.e., calcola l’hash) gli elementi applicando una funzione di hash sull’elemento stesso da inserire • La hash di ogni elemento da inserire viene calcolata invocando sull’elemento stesso il metodo definito in Object (a meno di non averlo overridato) public int hashCode() Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 51 Il metodo hashCode: specifiche per la sua implementazione • Ogni volta che viene invocato sullo stesso oggetto, deve restituire sempre lo stesso valore – A patto che l’oggetto non abbia cambiato di stato • Se due oggetti sono uguali secondo il metodo equals, l’invocazione al metodo su ognuno dei due oggetti deve dare lo stesso valore – Coerenza hashcode/equals – Come abbiamo visto la coerenza ordinamento naturale/equals • Il metodo hashCode definito in Object restituisce interi differenti per oggetti differenti – È implementato convertendo l’indirizzo di memoria dell’oggetto in un intero Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 52 26 6/3/2014 Esempio con String • La classe ha effettuato l’override sia di equals che di hashCode garantendo la coerenza hashCode/equals public class DemoHashCode { public static void main(String[] args) { String s1 = new String("Ciao"); String s2 = new String("Ciao"); System.out.println(s1.equals(s2)); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); } } S1 == s2 false! Nonostante questo, hanno stesso hashcode e sono equals Output: true 2100020 2100020 Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 53 Esempio con classe Persona senza override • La classe ha effettuato l’override di equals, ma non di hashCode public class DemoHashCode { public static void main(String[] args) { Persona p1 = new Persona("Micucci", "Daniela", "[email protected]"); Persona p2 = new Persona("Micucci", "Daniela", "[email protected]"); //abbiamo fatto override di equals che verifica nome e cognome System.out.println(p1.equals(p2)); //... ma non abbianmo fatto l'override di hashCode // ---> incoerenza hashCode/equals System.out.println(p1.hashCode()); System.out.println(p2.hashCode()); } } Output: true 1167165921 1442002549 Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 54 27 6/3/2014 Esempio con classe Persona corretta • Override di hashCode coerente con la def. di equals (solo nome e cognome) public class Persona implements Comparable<Persona> { // … @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((cognome == null) ? 0 : cognome.hashCode()); result = prime * result + ((nome == null) ? 0 : nome.hashCode()); return result; } public class DemoHashCode { // … public static void main(String[] args) { } Persona p1 = new Persona("Micucci", "Daniela", "[email protected]"); Persona p2 = new Persona("Micucci", "Daniela", "[email protected]"); //abbiamo fatto override di equals che verifica nome e cognome System.out.println(p1.equals(p2)); //... Con override di hashCode ---> coerenza hashCode/equals System.out.println(p1.hashCode()); System.out.println(p2.hashCode()); } } Output: true 1503986568 1503986568 Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 55 Interface Set: Esempio HashSet import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class DemoPersonaTreeSet { public static void main(String a[]){ Set<Persona> set = new HashSet<Persona>(); set.add(new Persona("Micucci", "Daniela", "[email protected]")); set.add(new Persona("Denaro", "Giovanni", "[email protected]")); set.add(new Persona("Tisato", "Francesco", "[email protected]")); set.add(new Persona("Sartori", "Fabio", "[email protected]")); Iterator<Persona> i = set.iterator(); while(i.hasNext()) System.out.println(i.next()); Elementi non ordinati Elementi duplicati non presenti //Anche se fosse un omonimo, non lo farebbe inserire: è un Set set.add(new Persona("Sartori", "Fabio", "[email protected]")); //Lo inserisce set.add(new Persona("Fiamberti", "Francesco", "[email protected]")); System.out.println("Set nuovo: "); i = set.iterator(); while(i.hasNext()) System.out.println(i.next()); } } Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework Output: Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Micucci, nome=Daniela] Set nuovo: Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Fiamberti, nome=Francesco] Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Micucci, nome=Daniela] 56 28 6/3/2014 Interface Map: Esempio TreeMap import import import import java.util.Collection; java.util.Iterator; java.util.Map; java.util.TreeMap; public class DemoPersonaTreeMap { public static void main(String a[]){ Map<Persona, String> map = new TreeMap<Persona, String>(); map.put(new Persona("Micucci", "Daniela", "[email protected]"), "Docente - Turno B"); map.put(new Persona("Denaro", "Giovanni", "[email protected]"), "Esercitatore - Turno B"); map.put(new Persona("Tisato", "Francesco", "[email protected]"), "Docente - Turno A"); map.put(new Persona("Sartori", "Fabio", "[email protected]"), "Esercitatore - Turno B"); Collection<String> values = map.values(); Iterator<String> i = values.iterator(); System.out.println("Valori:"); while(i.hasNext()) System.out.println(i.next()); Collection<Persona> keys = map.keySet(); Iterator<Persona> ii = keys.iterator(); System.out.println("Chiavi:"); while(ii.hasNext()) System.out.println(ii.next()); //Chiave già presente! Da specifica del metodo put, //sostituisce il vecchio valore con il nuovo map.put(new Persona("Sartori", "Fabio", "[email protected]"), "Esercitatore - Turno B"); map.put(new Persona("Fiamberti", "Francesco", "[email protected]"), "Tutor - Turno B"); ii = keys.iterator(); System.out.println("Chiavi:"); while(ii.hasNext()) System.out.println(ii.next()); } } Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework Chiavi ordinate Chiavi duplicate non presenti Output: Valori: Esercitatore ‐ Turno B Docente ‐ Turno B Esercitatore ‐ Turno B Docente ‐ Turno A Chiavi: Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Tisato, nome=Francesco] Chiavi: Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Fiamberti, nome=Francesco] Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Sartori, nome=Fabio] 57 Persona [cognome=Tisato, nome=Francesco] Interface Map: Esempio HashMap import import import import java.util.Collection; java.util.Iterator; java.util.Map; java.util.HashMap; public class DemoPersonaHashMap { public static void main(String a[]){ Map<Persona, String> map = new HashMap<Persona, String>(); map.put(new Persona("Micucci", "Daniela", "[email protected]"), "Docente - Turno B"); map.put(new Persona("Denaro", "Giovanni", "[email protected]"), "Esercitatore - Turno B"); map.put(new Persona("Tisato", "Francesco", "[email protected]"), "Docente - Turno A"); map.put(new Persona("Sartori", "Fabio", "[email protected]"), "Esercitatore - Turno B"); Collection<String> values = map.values(); Iterator<String> i = values.iterator(); System.out.println("Valori:"); while(i.hasNext()) System.out.println(i.next()); Collection<Persona> keys = map.keySet(); Iterator<Persona> ii = keys.iterator(); System.out.println("Chiavi:"); while(ii.hasNext()) System.out.println(ii.next()); //Chiave già presente! Da specifica del metodo put, //sostituisce il vecchio valore con il nuovo map.put(new Persona("Sartori", "Fabio", "[email protected]"), "Esercitatore - Turno C"); map.put(new Persona("Fiamberti", "Francesco", "[email protected]"), "Tutor - Turno B"); i = values.iterator(); System.out.println(“Valori:"); while(i.hasNext()) System.out.println(i.next()); } } Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework Chiavi non ordinati Chiavi duplicate non presenti Output: Valori: Docente ‐ Turno A Esercitatore ‐ Turno B Esercitatore ‐ Turno B Docente ‐ Turno B Chiavi: Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Micucci, nome=Daniela] Valori: Docente ‐ Turno A Tutor ‐ Turno B Esercitatore ‐ Turno B Esercitatore ‐ Turno C 58 Docente ‐ Turno B 29 6/3/2014 CLASSE COLLECTIONS Programmazione con Java: Collection Framework 59 Classe Collections • Collections è una classe che contiene metodi di utilità • Esempi: – sort(List) • Ordina una lista con un algoritmo veloce, che evita di riordinare elementi uguali – shuffle(List) • Scambia gli elementi di una lista in ordine casuale – reverse(List) • Inverte l’ordine degli elementi di una lista – fill(List, Object) • Sovrascrive ogni elemento della lista con l’oggetto specificato – copy(List dest, List src) • Copia la lista sorgente in quella di destinazione – binarySearch(List, Object) • Cerca un elemento in una lista ordinata usando un algoritmo di ricerca binaria • Nota: è possibile usare i metodi della classe Collections con qualsiasi classi di oggetti per cui sia stata definita una relazione d’ordine naturale tramite l’implementazione dell’interfaccia Comparable Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework 60 30 6/3/2014 Esempio di utilizzo: sort import import import import java.util.ArrayList; java.util.Collections; java.util.Iterator; java.util.List; public class DemoPersonaArrayList { public static void main(String a[]){ List<Persona> lista = new ArrayList<Persona>(); lista.add(new Persona("Micucci", "Daniela", "[email protected]")); lista.add(new Persona("Denaro", "Giovanni", "[email protected]")); lista.add(new Persona("Tisato", "Francesco", "[email protected]")); lista.add(new Persona("Sartori", "Fabio", "[email protected]")); Iterator<Persona> i = lista.iterator(); while(i.hasNext()) System.out.println(i.next()); Collections.sort(lista); System.out.println("Set ordinato: "); i = lista.iterator(); while(i.hasNext()) System.out.println(i.next()); } } Software Architecture Lab www.sal.disco.unimib.it Programmazione con Java: Collection Framework Output: Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Tisato, nome=Francesco] Persona [cognome=Sartori, nome=Fabio] Set ordinato: Persona [cognome=Denaro, nome=Giovanni] Persona [cognome=Micucci, nome=Daniela] Persona [cognome=Sartori, nome=Fabio] Persona [cognome=Tisato, nome=Francesco] 61 31