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) Collection
Set
List
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
>
>
> 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“
> Collection
creates
iterator() …
> 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 „“ jeweils nach dem Klassennamen der Collection
>
Der Syntax ähnelt dem Prinzip der „Templates“ in C++.
z.B. Typisierte Collection ab Java 1.5 Collection col = new ArrayList(); 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 col = new ArrayList(); 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 „“ vereinfacht sich die Iteration
HashMap map = new HashMap(); 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 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