Java Programmierung mit Datenstrukturen > Datenstrukturen in Java (Teil 2) Mark Egloff 2006 1 Java Programmierung mit Lernziel Heute Abend > Sie lernen verschieden Datenstrukturen und Ihre Bedeutung kennen z.B. „Arrays, Listen, Bäume, Maps“ > Sie kennen die Unterschiede und wissen wann welche Datenstruktur vorteilhaft eingesetzt werden sollte > Sie können eigene Datenstrukturen erstellen, diese sortieren und entsprechend bearbeiten Mark Egloff 2006 2 Java Programmierung mit Datenstrukturen in Java (Teil 2) Übersicht Datenstrukturen > Arrays Mehrdimensionale Felder um Werte oder Objekte in einer festen Reihenfolge aufzunehmen. Die maximale Grösse ist festgelegt > Liste Die Liste ist eine Datenstruktur zur dynamischen Speicherung von beliebig vielen Objekten. Objekte werden dabei einer Reihe nach abgelegt > Maps (Hashtabellen) „Maps“ sind Indexstrukturen (oder Assoziativspeicher), die die Elemente anhand eines Indexes oder Schlüssels verwalten > Bäume ( nächsten Abend…) Mehrere Elemente können auf andere Elmente verweisen. So entstehen Verknüpfungen und es können „Bäume“ realisiert werden Mark Egloff 2006 3 Java Programmierung mit Datenstrukturen in Java (Teil 2) Collections - Dynamische Datenstrukturen (1/2) > Bis jetzt haben wir Arrays kennen gelernt, die eine fixe Grösse haben. Nun möchten wir uns mehr mit dynamischen Datenstrukturen befassen. > Dynamische Datenstrukturen passen ihre Größe der Anzahl der Daten an, die sie aufnehmen. Dynamische Strukturen haben aber den Nachteil, dass zur Laufzeit Speicher angefordert und verwaltet werden muss, wenn Daten eingefügt werden. > Dieses Problem wurde mittlerweile von der Informatik erkannt, und der Trend geht wieder hin zu festen, nicht dynamischen Datenstrukturen vorwiegend Arrays, natürlich nur dort, wo dies auch möglich ist. > Eine der grössten Neuerungen, die die Java-2-Plattform eingeführt hat, ist die so genannte „Collection-API“. Ein Container als Objekt, welches wiederum Objekte aufnimmt und die Verwaltung der Elemente übernimmt. Mark Egloff 2006 4 Java Programmierung mit Datenstrukturen in Java (Teil 2) Collections - Dynamische Datenstrukturen (2/2) > In Java findet man alle Arten von dynamischen Datenstrukturen im Package „java.util“. Dort ist das „Collection-API“ untergebracht. > Als zentrale Basis des API‘s dienen die Interfaces „java.util.Collection“ und „java.util.Map“ > Es existiert eine Hilfsklasse „java.util.Collections“ – ähnlich wie bei den Arrays, die noch zusätzliche Unterstützungen anbietet ablegen holen Objekte Collection Mark Egloff 2006 5 Java Programmierung mit Datenstrukturen in Java (Teil 2) Das Basis- Interface „java.util.Collection“ (1/3) > „Collection“ bildet die generelle Basis, die fast alle Datenstrukturen implementiert (bis auf die Assoziativspeicher: Arrays und Maps) > Listen sowie Set‘s basieren auf diesem einfachem Interface. Durch die Schnittstelle „Collection“ erhalten alle Klassen einen gemeinsamen, äusseren Rahmen > Dadurch lassen sich Implementationen und ihre Algorithmen einfach austauschen um die jeweiligen Anforderungen abzudecken > Das Interface bietet Grund-Operationen für z.B. für Elemente hinzufügen, löschen, selektieren und finden Mark Egloff 2006 6 Java Programmierung mit Datenstrukturen in Java (Teil 2) Das Basis- Interface „java.util.Collection“ (2/4) <<interface>> Collection <<interface>> Set <<interface>> List <<interface>> SortedSet HashSet LinkedHashSet ArrayList TreeSet Mark Egloff 2006 LinkedList Vector Stack 7 Java Programmierung mit Datenstrukturen in Java (Teil 2) Das Basis- Interface „java.util.Collection“ (3/4) z.B. Nutzung des Interfaces „Collection“ mit versch. Implementationen import java.util.*; ... Collection col = new LinkedList(); col.add("Head"); col.add("first"); col.add("Java"); for(Iterator it = col.iterator(); it.hasNext(); ) System.out.print( it.next() + " "); Ausgabe: Head first Java dieselbe Reihenfolge wie eingefügt Mark Egloff 2006 8 Java Programmierung mit Datenstrukturen in Java (Teil 2) Das Basis- Interface „java.util.Collection“ (4/4) z.B. Nutzung des Interfaces „Collection“ mit versch. Implementationen import java.util.*; ... Collection col = new TreeSet(); col.add("Head"); col.add("first"); col.add("Java"); Einfacher Austausch der Implementation, Rest bleibt gleich, jedoch anderes Verhalten for(Iterator it = col.iterator(); it.hasNext(); ) System.out.print( it.next() + " "); Ausgabe: Head Java first sortierte Reihenfolge Mark Egloff 2006 9 Java Programmierung mit Datenstrukturen in Java (Teil 2) Auswahl der „richtigen“ Collection- Klasse Zugriff ohne Schlüssel keine Dupplikate ? ? Zugriff über Schlüssel Duplikate erlaubt << Set >> << Map >> << List >> Opt. Zugriff ? Sortiertes Iterieren Opt. Zugriff HashSet ? Sortiertes Iterieren Opt. Zugriff TreeSet singlethread ArrayList ? Einfügen nur am Kopf threadsafe LinkedList HashTable ? ? single thread HashMap TreeMap threadsafe Vector Stack Mark Egloff 2006 10 Java Programmierung mit Datenstrukturen in Java (Teil 2) > Listen in Java Mark Egloff 2006 11 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen > Die Liste ist eine Datenstruktur zur dynamischen Speicherung von beliebig vielen Objekten. > Dabei beinhaltet jedes Listenelement als Besonderheit einen Verweis auf das nächste Element, wodurch die Gesamtheit der Objekte zu einer Verkettung von Objekten wird. Listen sind somit stets linear. Mark Egloff 2006 12 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Vorteile/Nachteile gegenüber Arrays > Vorteil: Listen können beliebige Anzahl von Objekten aufnehmen bzw. verknüpfen. Sie müssen nicht auf eine bestimmte Grösse initialisiert werden. Neue Objekte können einfach am Ende angehängt werden. Speicher wird effizienter genutzt, keine leere, vorreservierte Plätze Beliebige Grösse > Nachteil: Es ist nur möglich vom einen zum nächsten Objekt in der Liste zu navigieren. Suchen nach Objekten ist aufwendig Einfügen /Entfernen von Objekten mitten in der Liste benötigt zusätzliche Logik um die Objekte wieder miteinander zu Verknüpfen. nur sequentieller Zugriff, macht es langsam zusätzlicher Verwaltungsaufwand Overhead um ein Objekt zu speichern, benötigt zusätzlicher Speicher Mark Egloff 2006 13 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Beispiel einer einfachen Liste (1/2) > Der folgende einfache Code zeigt wie ein Listenelement abgebildet werden könnte. Natürlich müssen Listen in Java nicht selber implementiert werden 1 DATA next Listenelement 1 2 DATA next Listenelement 2 class ListenElement { int index; Object data; ListenElement next 3 DATA null Listenelement 3 ListenElement index data next next } Mark Egloff 2006 14 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Beispiel einer einfachen Liste (2/2) ListenElment l1 = new ListenElement(1, "Alpha"); ListenElment l2 = new ListenElement(2, "Beta"); ListenElment l3 = new ListenElement(3, "Gamma"); l1.next = l2; l2.next = l3; 1 Alpha next Listenelement 1 2 Beta next Listenelement 2 Mark Egloff 2006 3 Gamma null Listenelement 3 15 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Übersicht verschiedener Implementationen > java.util.ArrayList Liste auf der Basis eines Arrays. Der interne Array wird bei Bedarf automatisch vergrössert. Ist nicht – threadsafe. > java.util.LinkedList Bildet eine verknüpfte Liste (ohne Array). Ist nicht – threadsafe. > java.util.Vector Liste auf der Basis eines Arrays. Der interne Array wird bei Bedarf automatisch vergrössert. Ist threadsafe. > java.util.Stack Basiert auf „Vector“, bildet eine „last-in-first-out“ (LIFO) Liste. Ist threadsafe. Mark Egloff 2006 16 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Übersicht verschiedener Implementationen interface Collection AbstractList Cloneable java.io.Serializable ArrayList interface List AbstractSequentialList Cloneable java.io.Serializable LinkedList Mark Egloff 2006 AbstractList Cloneable java.io.Serializable Vector Stack 17 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Auszug aus dem Interface „java.util.List“ Collection interf ace List +size:int +contains:boolean +iterator:Iterator +toArray:Object[] +toArray:Object[] +add:boolean +remove:boolean +containsAll:boolean +addAll:boolean +addAll:boolean +removeAll:boolean +retainAll:boolean +clear:void +equals:boolean +hashCode:int +get:Object +set:Object +add:void +remove:Object +indexOf:int +lastIndexOf:int +listIterator:ListIterator +listIterator:ListIterator +subList:List public interface List extends Collection { int size(); boolean add(Object o); void add(int index, Object o); boolean remove(Object o); Object remove(int index); Object get(int index); boolean set(int index); boolean removeAll(Collection c); void clear(); Iterator iterator(); ... } Der spezieller Unterschied gegenüber „Collection“ ist, dass man über einen Index auf die Elemente zugreifen kann Mark Egloff 2006 18 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Beispiel Vector import java.util.*; class Run { public static void main(String[] args) { List l = new Vector(); Instanzierung Kreis k = new Kreis(2.5f); l.add(k); Hinzufügen k = (Kreis) l.get(0); k = (Kreis) l.get(1); } Lesen // Laufzeitfehler // IndexOutOfBoundsExcpetion } Mark Egloff 2006 19 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Beispiel Stack import java.util.*; class Run { public static void main(String[] args) { Stack s = new Stack(); s.push("Head"); s.push("first"); s.push("Java"); } System.out.println( s.pop() ); // Java System.out.println( s.pop() ); // first } Mark Egloff 2006 20 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Performance verschiedener Implementationen Class LinkedList ArrayList Vector (threadsafe) Elemente Add Iterate Remove 1‘000 0.070 ms 3.06 ms 0.07 ms 100‘000 64.7 ms 432.0 ms 8.2 ms 1‘000 0.062 ms 5.24 ms 0.71 ms 100‘000 22.5 ms 532.3 ms 6314.4 ms 1‘000 0.067 ms 5.49 ms 0.71 ms 100‘000 47.1 ms 560.3 ms 6314.6 ms Nach 10 Durchläufen mit JRE 1.5, 2GHz Pentium M, 1GB RAM Die Wahl der richtigen Listen - Implementation ist entscheidend für die Performance Gewisse Listen lassen ein Fine-Tuning zu, um das Resizing-Verhalten zu optimieren (initialCapacity, capacityIncrement) Mark Egloff 2006 21 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Performance verschiedener Implementationen http://javolution.org/doc/benchmark.html Mark Egloff 2006 22 Java Programmierung mit Datenstrukturen in Java (Teil 2) Listen – Performance verschiedener Implementationen http://javolution.org/doc/benchmark.html Mark Egloff 2006 23 Java Programmierung mit Datenstrukturen in Java (Teil 2) > Set‘s in Java Mark Egloff 2006 24 Java Programmierung mit Datenstrukturen in Java (Teil 2) Set‘s > Sets oder auch „Mengen“ genannt sind eine spezielle Form von Listen, welche das gleiche Element nur einmal aufnehmen. Diese Art von Strukturen eignen sich bestens um eindeutige Werte aufzunehmen > Set‘s sind im allgemeinen langsamer als Listen, da sie zusätzlich eine Logik besitzen um die Eindeutigkeit sicherzustellen. Man unterscheidet zwischen geordneten (sortierten) sowie ungeordneten Set‘s > In Java bildet die Basis das Interface „java.util.Set“ bzw. „java.util.SortedSet“ ablegen Objekt equals() equals() equals() equals() holen equals() Mark Egloff 2006 25 Java Programmierung mit Datenstrukturen in Java (Teil 2) Set‘s – Übersicht verschiedener Implementationen > java.util.HashSet Schnelle Implementierung durch Hashing-Verfahren (HashMap). Ist nichtthreadsafe > java.util.TreeSet Mittels Binärbäume realisiert, die eine Sortierung ermöglichen. Ist nichtthreadsafe > java.util.LinkedHashSet Schnelle Mengenimplementierung unter Beibehaltung der Einfügereihenfolge. Ist nicht- threadsafe > java.util.EnumSet (seit Java 1.5). Eine spezielle Menge ausschließlich für Enum-Objekte. Ist nicht- threadsafe > java.util.concurrent.CopyOnWriteArraySet (seit Java 1.5) Schnelle Datenstruktur eignet sich für viele lesende Zugriffe Ist threadsafe Mark Egloff 2006 26 Java Programmierung mit Datenstrukturen in Java (Teil 2) Set‘s – Übersicht verschiedener Implementationen interf ace java.util.Collection Collection interf ace java.util.Set Cloneable java.io.Serializable j av a.util.TreeSet interf ace java.util.SortedSet Cloneable java.io.Serializable j av a.util.HashSet Mark Egloff 2006 AbstractCollection java.util.AbstractSet 27 Java Programmierung mit Datenstrukturen in Java (Teil 2) Set‘s – Auszug aus dem Interface „java.util.Set“ Collection interf ace java.util.Set +size:int +contains:boolean +iterator:Iterator +toArray:Object[] +toArray:Object[] +add:boolean +remove:boolean +containsAll:boolean +addAll:boolean +retainAll:boolean +removeAll:boolean +clear:void +equals:boolean +hashCode:int public interface Set extends Collection { int size(); boolean add(Object o); boolean remove(Object o); boolean removeAll(Collection c); void clear(); Iterator iterator(); // Enumeration ... } Mark Egloff 2006 28 Java Programmierung mit Datenstrukturen in Java (Teil 2) Set‘s – Beispiel mit HashSet import java.util.*; public class Run { public static void main(String args[]) { Set set = new HashSet(); set.add("Bernadine"); set.add("Elizabeth"); set.add("Gene"); set.add("Elizabeth"); Instanzierung Hinzufügen (Elizabeth 2x) System.out.println( set ) } } Ausgabe: [Gene, Bernadine, Elizabeth] unsortierte, zufällige Reihenfolge Mark Egloff 2006 29 Java Programmierung mit Datenstrukturen in Java (Teil 2) Set‘s – Beispiel mit TreeSet import java.util.*; public class Run { public static void main(String args[]) { Set set = new TreeSet(); set.add("Bernadine"); set.add("Elizabeth"); set.add("Gene"); set.add("Elizabeth"); Instanzierung Hinzufügen (Elizabeth 2x) System.out.println( set ) } } Ausgabe: [Bernadine, Elizabeth, Gene] sortierte Reihenfolge Mark Egloff 2006 30 Java Programmierung mit Datenstrukturen in Java (Teil 2) Set‘s – Funktionsweise von HashSet & TreeSet > java.util.HashSet HashSet verwendet intern die „java.util.HashMap“. Es wird beim Einfügen vom jeweiligen Objekt ein eindeutiger Wert (Identifikationsnummer, Hash) berechnet. Hierzu wird vom Objekt die Methode „hashCode()“ aufgerufen (vererbt von „java.lang.Object“). Diese muss für eigene Objekte überschrieben werden. > java.util.TreeSet Verwendet intern für die Sortierung das Interface „java.lang.Comparable“. Das jeweilige Objekt muss dieses Interface unterstützen, ansonsten wird eine „ClassCastException“ ausgelöst. Bei Objekten eigener Klassen muss dieses Interface implementiert werden. Mark Egloff 2006 31 Java Programmierung mit Datenstrukturen in Java (Teil 2) > Iteratoren in Java Mark Egloff 2006 32 Java Programmierung mit Datenstrukturen in Java (Teil 2) Iteration - Mit einem Iterator durch die Daten wandern > Um über generische und dynamische Datenstrukturen zu wandern wurde in der Informatik ein spezielles Design geschaffen das „Iterator“-Pattern. > Der „Iterator“ (oder „Cursor“) ist dabei ein Zeiger, mit dem über die Elemente einer Liste bzw. durch die Elemente iteriert werden kann. > Er verweist nur auf das aktuelle Objekt in einer Collection und kann mit entsprechenden Operationen auf das nächste Objekt verschoben werden Iterator next() next() Collection next() next() Objekt Mark Egloff 2006 33 Java Programmierung mit Datenstrukturen in Java (Teil 2) Iteration - Mit einem Iterator durch die Daten wandern > Das „Iterator“-Pattern erlaubt uns über eine beliebige Datenstruktur zu iterieren ohne die genaue Implementation zu kennen > Unsere Applikation bedient sich dabei nur einem zentralen Interface „Iterator“ << Interface>> Collection creates iterator() … << Interface>> Iterator hasNext() next() use MyApp main() creates ArrayList … ArrayListIterator has … Mark Egloff 2006 Iterator Pattern 34 Java Programmierung mit Datenstrukturen in Java (Teil 2) Iteration - Mit einem Iterator durch die Daten wandern > Für Iteratoren definiert die Java-Bibliothek zwei unterschiedliche Schnittstellen. Das hat historische Gründe. > Die Schnittstelle „java.util.Enumeration“ gibt es seit den ersten Java-Tagen; die Schnittstelle „java.util.Iterator“ gibt es seit Java 1.2 (seit der Collection-API). Der Typ „Iterator“ sollte in der Regel verwendet werden. > Beide Schnittstellen funktionieren nach dem demselben Prinzip. Sie besitzen eine Funktion, die jeweils das nächste Element erfragt z.B. „next()“ und eine Funktion, die ermittelt, ob es überhaupt ein nächstes Element gibt z.B. „hasNext()“. So wandert der Iterator Element für Element ab. Mark Egloff 2006 35 Java Programmierung mit Datenstrukturen in Java (Teil 2) Iteration – Auszug aus den Iterator Interfaces: interf ace java.util.Enume ration +hasMoreElement s:boolean +nextElement:Object interf ace java.util.Iterator +hasNext:boolean +next:Object +remove:void public interface Enumeration { boolean hasMoreElements(); Object nextElement(); } public interface Iterator { boolean hasNext(); Object next(); void remove(); } Der spezieller Unterschied ist hier, dass „Iterator“ noch die Möglichkeit bietet während der Iteration ein Element aus der Liste zu entfernen Mark Egloff 2006 36 Java Programmierung mit Datenstrukturen in Java (Teil 2) Iteration - Mit einem Iterator durch die Daten wandern z.B. Iteration mittels dem Interface „java.util.Iterator“ import java.util.*; ... Collection col = new LinkedList(); col.add("Head"); col.add(...); ...; // Iteration Iterator it = col.iterator(); while( it.hasNext() ) { String s = (String) it.next(); } // Casting von Object auf String Da „next()“ ein „java.lang.Object“ zurückliefert muss entsprechend gecastet werden. Achtung wegen „ClassCastException“ Mark Egloff 2006 37 Java Programmierung mit Datenstrukturen in Java (Teil 2) Iteration - Mit einem Iterator durch die Daten wandern > Seit Java 1.5 gibt es eine kürzere Version der „for“-Schleife um über eine Collection oder Array zu iterieren // herkömmliche Iteration for (Iterator it = col.iterator(); it.hasNext(); ) { String s = (String) it.next(); } // seit Java 1.5 for (Object o : col ) { String s = (String) o; } Achtung wegen „ClassCastException“. Die Collection „col“ kann ja alles mögliche an Objekten beinhalten Mark Egloff 2006 38 Java Programmierung mit Datenstrukturen in Java (Teil 2) Iteration – Collection während der Iteration bearbeiten Während einer Iteration ist es untersagt die Collection zu verändern z.B. Elemente hinzuzufügen oder zu entfernen. Wer es trotzdem tut erhält eine „ConcurrentModificationException“. for (Iterator it = col.iterator(); it.hasNext(); ) { String s = (String) it.next(); if ( ... ) col.remove( s )) ...; Laufzeitfehler! } > Das Interface „Iterator“ bietet eine Methode „remove()“ an um während der Iteration gleich das aktuelle Elemente zu entfernen for (Iterator it = col.iterator(); it.hasNext(); ) { String s = (String) it.next(); if ( ... ) it.remove() ) ...; richtig !! } Mark Egloff 2006 39 Java Programmierung mit Datenstrukturen in Java (Teil 2) Generische Datentypen in der Collection-API (1/5) > Ein grosses Problem bei der Handhabung von Collections ist, dass sie prinzipiell offen für jeden Typ sind, da sie Objekte vom allgemeinsten Typ „java.lang.Object“ beim Speichern entgegennehmen und diesen auch als Rückgabe liefern. Problem: Objekte gehen als Ihre Datentypen (Fussball, Fisch, Gitarre, Auto) rein und kommen aber als generisches Objekt wieder raus Casting ist notwendig ! Mark Egloff 2006 40 Java Programmierung mit Datenstrukturen in Java (Teil 2) Generische Datentypen in der Collection-API (2/5) > Falsches Casting bzw. das Auftreten von „ClassCastException“ zur Laufzeit ist daher keine Seltenheit. z.B. falsches Casting bei einer Collection mit gemixten Datentypen Collection col = new ArrayList(); col.add( "Text…" ); col.add( new Integer(123) ); // mixed types for (Iterator it = col.iterator(); it.hasNext(); ) { String s = (String) it.next(); } Mark Egloff 2006 // Laufzeitfehler beim 2. Element 41 Java Programmierung mit Datenstrukturen in Java (Teil 2) Generische Datentypen in der Collection-API (3/5) > Um diese Handhabung zu vereinfachen und um „ClassCastExceptions“ zu vermeiden, wurde seit Java 1.5 eine Möglichkeit geschaffen um den genauen Typ anzugeben Kompromisslösung mittels „Generics“: Es wird eine Collection für einen Typ (z.B. Fisch) geschaffen . Alle gehen als Fische rein und kommen auch wieder als Fische raus Mark Egloff 2006 42 Java Programmierung mit Datenstrukturen in Java (Teil 2) Generische Datentypen in der Collection-API (4/5) > Bei der Instanzierung muss die Klasse der Elemente angegeben werden. Diese Typangabe erfolgt mit „<ClassName>“ jeweils nach dem Klassennamen der Collection > Der Syntax ähnelt dem Prinzip der „Templates“ in C++. z.B. Typisierte Collection ab Java 1.5 Collection<String> col = new ArrayList<String>(); col.add( "Text…" ); col.add( new Integer(123) ); // Compilerfehler, nur String erlaubt Mark Egloff 2006 43 Java Programmierung mit Datenstrukturen in Java (Teil 2) Generische Datentypen in der Collection-API (5/5) > Bei diesen typisierten Collections muss dann später nicht mehr gecastet werden. z.B. Typisierte Collection ab Java 1.5 List<String> col = new ArrayList<String>(); col.add( "Head" ); col.add( "first" ); col.add( "Java" ); // kein Casting mehr notwendig: String first = col.get(1); for (String s : col ) { System.out.println(s); } // „get()“ gibt nun direkt String zurück // direkter String-Iterator Mark Egloff 2006 44 Java Programmierung mit Datenstrukturen in Java (Teil 2) > Maps in Java Mark Egloff 2006 45 Java Programmierung mit Datenstrukturen in Java (Teil 2) Maps > Eine Map ist ein Assoziativspeicher, der Objekte unter Verwendung einer Zuordnung (Index) verwaltet. > Eine Map sind wie Postfächer anzusehen. Sie speichern die Objekte anhand eines zusätzlichen Schlüssels (Key) ab, welcher als Index dient. Dieser Schlüssel ist natürlich wiederum ein Objekt. Key Key ablegen holen Daten Daten Map Mark Egloff 2006 46 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s in Java > In Java bildet das Interface „java.util.Map“ die Basis für alle Maps. Sie ist nicht kompatibel zum Interface „java.util.Collection“ > Die Java Collection-API bietet wie bei den Set‘s entsprechend eine sortierte und unsortierte implementationen an. Übersicht verschiedener Implementationen > java.util.HashMap Schnelle Implementierung durch Hashing-Verfahren. Ist nicht- threadsafe > java.util.Hashtable Schnelle Implementierung durch Hashing-Verfahren. Ist threadsafe > java.util.TreeMap Besitzt ein langsamerer Zugriff, doch dafür sind alle Schlüssel sortiert. Sie sortiert die Schlüssel in einen Binärbaum ein. Ist nicht- threadsafe Mark Egloff 2006 47 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Übersicht verschiedener Implementationen interf ace Map Dictionary Cloneable java.io.Serializable Hashtable AbstractMap Map Cloneable java.io.Serializable HashMap AbstractMap AbstractMap SortedMap Cloneable java.io.Serializable TreeMap empty :boolean Mark Egloff 2006 48 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Auszug aus dem Interface „java.util.Map“ interf ace Map +size:int +containsKey:boolean +containsValue:boolean +get:Object +put:Object +remove:Object +putAll:void +clear:void +keySet:Set +values:Collection +entrySet:Set +equals:boolean +hashCode:int public interface Map { int size(); boolean containsKey(Object key); boolean containsValue(Object value); Object put(Object key, Object value); Object get(Object key); Object remove(Object key); void clear(); ... } Mark Egloff 2006 49 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Beispiel mit HashMap, Standard Schlüssel (1/2) public class Kunde { public int kndNnummer; public String vorName; public String nachName; public Kunde( int kndNummer, String vorName, String nachName) { this.kndNummer = kndNummer; this.vorName = vorName; this.nachName = nachName; } } Mark Egloff 2006 50 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Beispiel mit HashMap, Standard Schlüssel (2/2) import java.util.*; public class Run { public static void main(String args[]) { Map map = new HashMap(); map.put( new Integer(112), new Kunde(112, "Hans", "Müller")); map.put( new Integer(113), new Kunde(113, "Max", "Moritz")); Kunde k1 = (Kunde) map.get( new Integer(112) ); Kunde k2 = (Kunde) map.get( new Integer(113) ); } } Als Schlüssel muss ein Objekt bzw. Klasse verwendet werden, welche eine Implementation der „hashCode()“ Methode besitzt Mark Egloff 2006 51 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Beispiel mit HashMap , Ieration (1/2) z.B. Iteration durch eine Map, durch alle Schlüssel und alle Elemente // herkömmliche Iteration Iterator it = map.keySet().iterator(); while( it.hasNext() ) { Object key = it.next(); Kunde k = ( Kunde ) map.get( key ); System.out.println( k ); // unsortierte Ausgabe } // ab Java 1.5 mit erweiterter for- Schleife for ( Object key : map.keySet() ) { Kunde k = ( Kunde ) map.get( key ); System.out.println( k ); // unsortierte Ausgabe } Mark Egloff 2006 52 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Beispiel mit HashMap, Iteration (2/2) z.B. Iteration durch eine Map, durch alle Schlüssel und alle Elemente // ab Java 1.5 mit der Benützung von „<Generics>“ vereinfacht sich die Iteration HashMap<Integer,Kunde> map = new HashMap<Integer,Kunde>(); map.put( new Integer(112), new Kunde(112, "Hans", "Müller")); ... for ( Integer key : map.keySet() ) { // kein Casting notwendig Kunde k = map.get( key ); System.out.println( k ); } Der Einsatz von <Generics> ist nur möglich falls die Typen für die Schlüssel sowie für die Datenelemente immer gleich sind Mark Egloff 2006 53 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Beispiel mit TreeMap (1/2) import java.util.*; public class Run { public static void main(String args[]) { Map map = new TreeMap(); Einfacher Austausch der Implementation. map.put( new Integer(112), new Kunde(112, "Hans", "Müller")); map.put( new Integer(113), new Kunde(113, "Max", "Moritz")); Kunde k1 = (Kunde) map.get( new Integer(112) ); Kunde k2 = (Kunde) map.get( new Integer(113) ); } } Als Schlüssel muss ein Objekt bzw. Klasse verwendet werden, welche das Interface „java.lang.Comparable“ implementiert Mark Egloff 2006 54 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Beispiel mit TreeMap (2/2) z.B. Iteration durch eine Map, durch alle Schlüssel und alle Elemente // herkömmliche Iteration Iterator it = map.keySet().iterator(); while( it.hasNext() ) { Object key = it.next(); Kunde k = ( Kunde ) map.get( key ); System.out.println( k ); // sortierte Ausgabe } Da „map“ hier eine SortedMap ist, erfolgt die Iteration durch die Schlüssel sortiert Mark Egloff 2006 55 Java Programmierung mit Datenstrukturen in Java (Teil 2) Map‘s – Funktionsweise von HashMap & TreeMap > java.util.HashMap Es wird beim Einfügen vom jeweiligen Key-Objekt ein eindeutiger Wert (Identifikationsnummer, Hash) berechnet. Hierzu wird vom Key die Methode „hashCode()“ aufgerufen (vererbt von „java.lang.Object“). Diese muss für eigene Key-Klassen überschrieben werden. > java.util.TreeMap Verwendet intern für die Sortierung das Interface „java.lang.Comparable“. Das jeweilige Key-Objekt muss dieses Interface unterstützen, ansonsten wird eine „ClassCastException“ ausgelöst. Bei eigenen Keys muss dieses Interface implementiert werden. Mark Egloff 2006 56 Java Programmierung mit Datenstrukturen in Java (Teil 2) > Hilfsklasse „Collections“ Mark Egloff 2006 57 Java Programmierung mit Datenstrukturen in Java (Teil 2) Hilfsklasse „java.util.Collections“ > Ähnlich wie bei den Arrays (java.util.Arrays) existiert auch für die Collections und Maps eine Hilfsklasse mit nützlichen statischen Funktionen: „java.util.Collections“ > Die Klasse bietet bekannte Dinge wie binäre Suche, Ermittlung des min/max Elementes, Sortierung sowie Generierung von Zufallsreihenfolgen an. Eine wesentliche weitere Funktionalität sind die „Factory“ - Methoden um „threadsafe“ oder „immutable“ Collections zu erzeugen. z.B. Erzeugung einer „threadsafe“ - Liste mittels „Collections“ Collection c = new ArrayList(); // ArrayList ist nicht threadsafe ... Collection sc = Collections.synchronizedCollection(c); sc.add( "Text…" ); Mark Egloff 2006 58 Java Programmierung mit Datenstrukturen in Java (Teil 2) > Handhabungen von Collections Mark Egloff 2006 59 Java Programmierung mit Datenstrukturen in Java (Teil 2) Collections sind Objekte > Collections sind normale Objekte, es gelten somit die gleichen bzw. ähnliche Gesetze, wie wir schon kennen gelernt haben. > Alle Implementationen von „java.util.Collection“ sowie „java.util.Map“ stammen automatisch von „java.lang.Object“ ab. > All diese Container besitzen somit eine „equals()“ sowie eine „clone()“ Methode. Doch wie wir schon bei den Arrays gesehen haben, müssen wir die Details hierzu anschauen z.B. Vergleich von 2 Collections Collection c1 = new ArrayList();... Collection c2 = new ArrayList();... ... if ( c1.equals(c2) ) geht das ?? Was passiert hier genau? Mark Egloff 2006 60 Java Programmierung mit Datenstrukturen in Java (Teil 2) Vergleichen von Collections (1/2) > Beide Interfaces „java.util.Collection“ sowie „java.util.Map“ bieten die Methode „equals()“ an. > Die Implementation dieser Methode befindet sich bei der jeweiligen Implementations-Klasse des Interfaces (z.B. „java.util.ArrayList“) . Deshalb lohnt es sich jeweils ein Blick in die JavaDoc der jeweiligen Klasse zu werfen > Die Klassen im Java API verhalten sich nach den folgenden Regeln. Eine Collection ist gleich wenn … 1. sie von derselben Klassen-Familie sind z.B. (List != Set) 2. sie die gleiche Anzahl an Elementen in gleicher Reihenfolge aufweisen 3. Im Falle von „Map“ die Elemente gleich indexiert sind 4. die jeweiligen Element mit „a1.equals(b1)== true“ ergeben Mark Egloff 2006 61 Java Programmierung mit Datenstrukturen in Java (Teil 2) Vergleichen von Collections (2/2) z.B. Anwendung der „equals()“ Methode bei „gleichen“ Klasse Collection c1 = new ArrayList(); Collection c2 = new LinkedList(); ... if (c1.equals(c2)) ... // funktioniert richtig Bei Elementen eigener Klassen muss die „equals()“ Methode implementiert sein z.B. Anwendung der „equals()“ Methode bei „unterschiedlicher“ Klasse Collection c1 = new ArrayList(); Collection c2 = new HashSet(); ... if (c1.equals(c2)) ... // immer „false“ ja nie machen ! Mark Egloff 2006 62 Java Programmierung mit Datenstrukturen in Java (Teil 2) Elemente in Collections prüfen mit „contains()“ > Die Collection Klassen bieten eine Methode an, die überprüft ob sich ein gleiches Element schon in der Collection befindet: „contains()“ > Bei „Map“ existieren entsprechend 2 „containsXXX()“ Methoden. Einmal für die Schlüssel „containsKey()“ und einmal für die Elemente selber „containsValue()“ > Diese Methode ruft intern von jedem Element die „equals()“ Methode auf. Bei Elementen eigener Klassen muss deshalb die „equals()“ Methode implementiert sein z.B. Anwendung der „contains()“ Methode Collection c = new ArrayList(); ... if (c.contains( "DATA" )) ... Mark Egloff 2006 63 Java Programmierung mit Datenstrukturen in Java (Teil 2) Klonen von Collections > Um eine Collection zu klonen müssen wir die „clone()“ Methode von der jeweiligen Implementations-Klasse aufrufen. Die Interfaces „Collection“ oder „Map“ kennen das „clone()“ selber nicht. > Die „clone()“ Methode selber kopiert nur den Container (die Hülle). Die Elemente selber werden nicht kopiert (Shallow Copy oder Flache Kopie). Es verhält sich somit gleich wie bei den Arrays. > Ein „deep“- Copy existiert nicht in Java, man müsste selber eine entsprechende Hilfs-Methode schreiben z.B. Anwendung der „clone()“ Methode ArrayList al = new ArrayList(); ... Collection c = (Collection) al.clone(); Mark Egloff 2006 64 Java Programmierung mit Datenstrukturen in Java (Teil 2) Collections und Arrays > Manchmal muss man zwischen Arrays und Collections wechseln. Hierzu werden von den Klassen entsprechende Methoden angeboten > Das Interface „java.util.Collection“ bietet die Methode „toArray()“ an um die Collection in ein Array zu überführen > „java.util.Arrays“ bietet eine Hilfsmethode um einen Array in eine Liste zu wandeln „Arrays.asList()“ z.B. Collection in Array wandeln und wieder zurück Collection c = new ArrayList(); c.add( "Java" ); ... String[] sArray = (String[]) c.toArray( new String[]{} ); c = Arrays.asList(sArray); Mark Egloff 2006 65