Java SE 8 Standard-Bibliothek  
Professionelle Bücher. Auch für Einsteiger.
 
Inhaltsverzeichnis

Vorwort
1 Neues in Java 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 4 Datenstrukturen und Algorithmen
Pfeil 4.1 Datenstrukturen und die Collection-API
Pfeil 4.1.1 Designprinzip mit Schnittstellen, abstrakten und konkreten Klassen
Pfeil 4.1.2 Die Basisschnittstellen Collection und Map
Pfeil 4.1.3 Die Utility-Klassen Collections und Arrays
Pfeil 4.1.4 Das erste Programm mit Container-Klassen
Pfeil 4.1.5 Die Schnittstelle Collection und Kernkonzepte
Pfeil 4.1.6 Schnittstellen, die Collection erweitern, und Map
Pfeil 4.1.7 Konkrete Container-Klassen
Pfeil 4.1.8 Generische Datentypen in der Collection-API
Pfeil 4.1.9 Die Schnittstelle Iterable und das erweiterte for
Pfeil 4.2 Listen
Pfeil 4.2.1 Erstes Listen-Beispiel
Pfeil 4.2.2 Auswahlkriterium ArrayList oder LinkedList
Pfeil 4.2.3 Die Schnittstelle List
Pfeil 4.2.4 ArrayList
Pfeil 4.2.5 LinkedList
Pfeil 4.2.6 Der Feld-Adapter Arrays.asList(…)
Pfeil 4.2.7 ListIterator *
Pfeil 4.2.8 toArray(…) von Collection verstehen – die Gefahr einer Falle erkennen
Pfeil 4.2.9 Primitive Elemente in Datenstrukturen verwalten
Pfeil 4.3 Mengen (Sets)
Pfeil 4.3.1 Ein erstes Mengen-Beispiel
Pfeil 4.3.2 Methoden der Schnittstelle Set
Pfeil 4.3.3 HashSet
Pfeil 4.3.4 TreeSet – die sortierte Menge
Pfeil 4.3.5 Die Schnittstellen NavigableSet und SortedSet
Pfeil 4.3.6 LinkedHashSet
Pfeil 4.4 Queues (Schlangen) und Deques
Pfeil 4.4.1 Queue-Klassen
Pfeil 4.4.2 Deque-Klassen
Pfeil 4.4.3 Blockierende Queues und Prioritätswarteschlangen
Pfeil 4.4.4 PriorityQueue
Pfeil 4.5 Stack (Kellerspeicher, Stapel)
Pfeil 4.5.1 Die Methoden von java.util.Stack
Pfeil 4.6 Assoziative Speicher
Pfeil 4.6.1 Die Klassen HashMap und TreeMap
Pfeil 4.6.2 Einfügen und Abfragen des Assoziativspeichers
Pfeil 4.6.3 Über die Bedeutung von equals(…) und hashCode() bei Elementen
Pfeil 4.6.4 Eigene Objekte hashen
Pfeil 4.6.5 LinkedHashMap und LRU-Implementierungen
Pfeil 4.6.6 IdentityHashMap
Pfeil 4.6.7 Das Problem veränderter Elemente
Pfeil 4.6.8 Aufzählungen und Ansichten des Assoziativspeichers
Pfeil 4.6.9 Die Arbeitsweise einer Hash-Tabelle *
Pfeil 4.6.10 Die Properties-Klasse
Pfeil 4.7 Mit einem Iterator durch die Daten wandern
Pfeil 4.8 Iterator-Schnittstelle
Pfeil 4.8.1 Der Iterator kann (eventuell auch) löschen
Pfeil 4.8.2 Operationen auf allen Elementen durchführen
Pfeil 4.8.3 Einen Zufallszahlen-Iterator schreiben
Pfeil 4.8.4 Iteratoren von Sammlungen, das erweiterte for und Iterable
Pfeil 4.8.5 Fail-Fast-Iterator und die ConcurrentModificationException
Pfeil 4.8.6 Die Schnittstelle Enumerator *
Pfeil 4.9 Algorithmen in Collections
Pfeil 4.9.1 Die Bedeutung von Ordnung mit Comparator und Comparable
Pfeil 4.9.2 Sortieren
Pfeil 4.9.3 Den größten und kleinsten Wert einer Collection finden
Pfeil 4.9.4 Nichtänderbare Datenstrukturen, immutable oder nur lesen?
Pfeil 4.9.5 Null Object Pattern und leere Sammlungen/Iteratoren zurückgeben
Pfeil 4.9.6 Echte typsichere Container
Pfeil 4.9.7 Mit der Halbierungssuche nach Elementen fahnden
Pfeil 4.9.8 Ersetzen, Kopieren, Füllen, Umdrehen, Rotieren *
Pfeil 4.9.9 Listen durchwürfeln *
Pfeil 4.9.10 Häufigkeit eines Elements *
Pfeil 4.9.11 Singletons *
Pfeil 4.9.12 nCopies(…) *
Pfeil 4.10 Datenstrukturen mit Änderungsmeldungen
Pfeil 4.10.1 Das Paket javafx.collections
Pfeil 4.10.2 Fabrikmethoden in FXCollections
Pfeil 4.10.3 Änderungen melden über InvalidationListener
Pfeil 4.10.4 Änderungen melden über XXXChangeListener
Pfeil 4.10.5 Change-Klassen
Pfeil 4.10.6 Weitere Hilfsmethoden einer ObservableList
Pfeil 4.10.7 Melden von Änderungen an Arrays
Pfeil 4.10.8 Transformierte FXCollections
Pfeil 4.10.9 Weitere statische Methoden in FXCollections
Pfeil 4.11 Stream-API
Pfeil 4.11.1 Stream erzeugen
Pfeil 4.11.2 Terminale Operationen
Pfeil 4.11.3 Intermediäre Operationen
Pfeil 4.11.4 Streams mit primitiven Werten
Pfeil 4.11.5 Stream-Beziehungen, AutoCloseable
Pfeil 4.11.6 Stream-Builder
Pfeil 4.11.7 Spliterator
Pfeil 4.11.8 Klasse StreamSupport
Pfeil 4.12 Spezielle threadsichere Datenstrukturen
Pfeil 4.12.1 Zu Beginn nur synchronisierte Datenstrukturen in Java 1.0
Pfeil 4.12.2 Nicht synchronisierte Datenstrukturen in der Standard-Collection-API
Pfeil 4.12.3 Nebenläufiger Assoziativspeicher und die Schnittstelle ConcurrentMap
Pfeil 4.12.4 ConcurrentLinkedQueue
Pfeil 4.12.5 CopyOnWriteArrayList und CopyOnWriteArraySet
Pfeil 4.12.6 Wrapper zur Synchronisation
Pfeil 4.12.7 Blockierende Warteschlangen
Pfeil 4.12.8 ArrayBlockingQueue und LinkedBlockingQueue
Pfeil 4.12.9 PriorityBlockingQueue
Pfeil 4.12.10 Transfer-Warteschlangen – TransferQueue und LinkedTransferQueue
Pfeil 4.13 Google Guava (Google Collections Library)
Pfeil 4.13.1 Beispiel Multi-Set und Multi-Map
Pfeil 4.13.2 Datenstrukturen aus Guava
Pfeil 4.13.3 Utility-Klassen von Guava
Pfeil 4.13.4 Prädikate
Pfeil 4.13.5 Transformationen
Pfeil 4.14 Die Klasse BitSet für Bitmengen *
Pfeil 4.14.1 Ein BitSet anlegen
Pfeil 4.14.2 BitSet füllen und Zustände erfragen
Pfeil 4.14.3 Mengenorientierte Operationen
Pfeil 4.14.4 Weitere Methoden von BitSet
Pfeil 4.14.5 Primzahlen in einem BitSet verwalten
Pfeil 4.15 Zum Weiterlesen
 
Zum Seitenanfang

4.10Datenstrukturen mit Änderungsmeldungen Zur vorigen ÜberschriftZur nächsten Überschrift

Datenstrukturen aus den Paketen java.util und java.util.concurrent, wie ArrayList, HashSet, TreeMap, ConcurrentHashMap, haben die Aufgabe, Daten zu verwalten und Zugriffe zur Verfügung zu stellen. Was diese Datenstrukturen (und Arrays) nicht können, ist das Melden von Veränderungen. Wenn zum Beispiel eine Standardsammlung ein neues Element bekommt, kann sich kein Interessent bei der Datenstruktur anmelden, der über die Neuerung informiert wird und zum Beispiel das neue Element verarbeitet. Was wir uns wünschen, ist eine Listener-Benachrichtigung über alle Änderungen an der Sammlung an sich (nicht an den Elementen in der Sammlung).

 
Zum Seitenanfang

4.10.1Das Paket javafx.collections Zur vorigen ÜberschriftZur nächsten Überschrift

Im Zuge von JavaFX sind neue Datenstrukturen zur Java SE gestoßen, allerdings finden sich diese nicht im Paket java.util, sondern im Paket javafx.collections inklusive eines Unterpakets javafx.collections.transformation. Die neuen Datenstrukturen erweitern die java.util-Datenstrukturen List, Set und Map und können Veränderungen melden.

Typen

Funktion

ObservableList, ObservableSet, ObservableMap

Schnittstellen für die änderungsmeldenden Typen

ObservableArray, ObservableFloatArray, ObservableIntegerArray

Schnittstellen für die änderungsmeldenden Arrays

FXCollections

Klasse, die Exemplare der änderungsmeldenden Typen erzeugt

ListChangeListener, SetChangeListener, MapChangeListener, ArrayChangeListener

Listener-Schnittstellen mit onChanged(…)-Methoden

ListChangeListener.Change, SetChangeListener.Change, MapChangeListener.Change

Ereignis-Objekte, an denen der Typ der Änderung abzulesen ist

WeakListChangeListener, WeakSetChangeListener, WeakMapChangeListener

spezielle Wrapper-Klassen, falls die Elemente der Datenstruktur schwache Referenzen sind

FilteredList, SortedList

zwei änderungsmeldende Klassen aus javafx.collections.transformation, die eine spezielle Sicht auf die Daten bieten

ObservableArrayBase, ObservableListBase

abstrakte Basisklassen für eigene änderungsmeldende Klassen

Tabelle 4.5Alle Typen des Pakets javafx.collections[.transformation]

Die Schnittstelle ObservableList erweitert java.util.List, ObservableSet erweitert java. util.Set und ObservableMap erweitert java.util.Map. Somit bieten die neuen ObservableXXX-Typen mindestens die gleichen Methoden wie die bekannten Basistypen.

 
Zum Seitenanfang

4.10.2Fabrikmethoden in FXCollections Zur vorigen ÜberschriftZur nächsten Überschrift

Alle änderungsmeldenden Datenstrukturen sind nur über die genannten ObservableXXX-Schnittstellen beschrieben, und es gibt keine sichtbaren implementierenden Klassen, die über einen Konstruktor angelegt werden. Als Erzeuger der Typen deklariert FXCollections genau zehn Fabrikmethoden, die alle mit dem Präfix observable beginnen:

class javafx.collections.FXCollections
  • static <E> ObservableList<E> observableArrayList()

  • static <E> ObservableList<E> observableArrayList(E... items)

  • static <K,V> ObservableMap<K,V> observableHashMap()

  • static <E> ObservableSet<E> observableSet(E... elements)

Die Datenstrukturen lassen sich über die statischen Methoden leer oder bereits gefüllt anlegen, wobei die Konstruktoren dann Elemente direkt über eine variable Argumentliste annehmen.

Eine weitere Möglichkeit ist, existierende Sammlungen zu übergeben (und natürlich auch andere änderungsmeldende Sammlungen) und auf diese Weise die änderungsmeldende Sammlung zu initialisieren:

class javafx.collections.FXCollections
  • static <E> ObservableList<E> observableArrayList(Collection<? extends E> col)

  • static <E> ObservableList<E> observableList(List<E> list)

  • static <E> ObservableList<E> observableList(List<E> list, Callback<E,Observable[]> extractor)

  • static <E> ObservableSet<E> observableSet(Set<E> set)

  • static <K,V> ObservableMap<K,V> observableMap(Map<K,V> map)

  • static <E> ObservableList<E> observableArrayList(Callback<E,Observable[]> extractor)

Die letzte Methode in der Liste tanzt etwas aus der Reihe, da sie auf den Typ javafx.beans.Callback und javafx.beans.Observable (nicht java.util.Observable) aufbaut und somit eine Abhängigkeit zu einem anderen JavaFX-Paket hat.

[»]Hinweis

Keine der Fabrikmethoden schreibt direkt auf die darunterliegende Sammlung durch. Es sind also keine Wrapper. Mit der übergebenen Sammlung wird lediglich die neue Datenstruktur initialisiert, um am Anfang keine Ereignisse auszulösen.

Eine Methode observableTreeMap(…) fehlt, da hier ein Sortierkriterium nötig wäre; wer einen geordneten Assoziativspeicher benötigt, kann so etwas wie FXCollections.observableMap(new TreeMap<>(comparator)) einsetzen.

Überhaupt ist interessant, dass die Methodenamen auf der einen Seite verraten, welche Implementierung eingesetzt wird (observableArrayList) und dann wiederum nicht (observableSet), wobei hinter Letzterem ein HashSet steht, die Elemente also daher eine gültige hashCode()-Methode implementieren müssen, auch wenn sie sonst überhaupt nichts mit Hashing zu tun haben. Wer ein änderungsmeldendes TreeSet erzeugen möchte, nutzt den gleichen Trick wie auch bei der TreeMap, verwendet also FXCollections.observableSet(new TreeSet<>(comparator)).

[»]Hinweis

Änderungsmeldende Datenstrukturen können natürlich auch geschachtelt werden. Es spricht nichts dagegen, mehrere ObservableListen in eine ObservableList zu setzen, um so eine Tabelle nachzubauen. Allerdings heißt das nicht, dass eine Änderung an der »inneren« Liste zur Meldung der äußeren Liste führt.

 
Zum Seitenanfang

4.10.3Änderungen melden über InvalidationListener Zur vorigen ÜberschriftZur nächsten Überschrift

An änderungsmeldenden Datenstrukturen lassen sich zwei Arten von Listenern setzen, die über Änderungen informieren:

  1. Zunächst erweitern alle ObservableXXX-Schnittstellen die JavaFX-Schnittstelle javafx.beans. Observable und lassen sich so mit einem InvalidationListener beobachten. Das dient dazu, herauszufinden, ob sich ein beobachteter Wert (in diesem Fall die Datenstruktur) irgendwie verändert hat. Das sagt aber nichts über die genaue Veränderung aus. Meldungen dieser Art reichen aber oft aus und sind unkompliziert. Anwendungen gibt es viele: Nehmen wir an, wir stellen ein geometrisches Objekt auf dem Bildschirm dar. Das Objekt selbst kann aus einer Liste von Punkten bestehen. Ändert sich die Liste, reicht ein an die Liste angehängter InvalidationListener aus, um dort bei einer Änderung den Befehl zum Neuzeichnen zu geben.

  2. Der InvalidationListener informiert nur, dass die Datenstruktur »invalide« ist, aber nicht, was genau mit der Datenstruktur passiert ist. Um das herauszufinden, etwa an welcher Stelle etwas in einer Liste passiert ist, gibt es für die ObservableXXX-Typen extra XXXChangeListener mit sehr vielen Statusinformationen. Die versendeten Change-Objekte sind etwas teuer in der Herstellung, sodass sie nur dann zum Einsatz kommen sollten, wenn die feinen Informationen auch verwendet werden, sonst ist ein InvalidationListener besser.

 
Zum Seitenanfang

4.10.4Änderungen melden über XXXChangeListener Zur vorigen ÜberschriftZur nächsten Überschrift

Im Folgenden schauen wir uns erst die Behandlung der änderungsmeldenden Datenstrukturen an, Arrays werden folgen. Drei ObservableXXX-Typen bieten eigene überladene Methoden addListener(…)/removeListener(…) für XXXChangeListener, die die genauen Änderungen in den Datenstrukturen melden:

Typ

An-/Abmelde-Methoden, Rückgabe void

ObservableList<E>

addListener(ListChangeListener<? super E> listener)
removeListener(ListChangeListener<? super E> listener)

ObservableSet<E>

addListener(SetChangeListener<? super E> listener)
removeListener(SetChangeListener<? super E> listener)

ObservableMap<K,V>

addListener(MapChangeListener<? super K,? super V> listener)
removeListener(MapChangeListener<? super K,? super V> listener)

Tabelle 4.6Alle addListener(…)/removeListener(…)-Methoden von drei ObservableXXX-Typen

Argumente der xxxListener(…)-Methoden sind XXXChangeListener-Objekte. Werden die Listener hinzugefügt und folgt dann eine Änderung an der Datenstruktur, wird sie diese Änderung an den Listener melden. Es können beliebig viele Listener hinzugefügt werden.

Schauen wir uns diese XXXChangeListener-Schnittstellen genauer an (WeakXXXChangeListener außen vor gelassen); sie verfügen alle über genau eine onChanged(…)-Methode:

XXXChangeListener-Typ

void-Methode

ListChangeListener

onChanged(ListChangeListener.Change<? extends E> c)

SetChangeListener

onChanged(SetChangeListener.Change<? extends E> change)

MapChangeListener

onChanged(MapChangeListener.Change<? extends K,? extends V> change)

Tabelle 4.7onChanged(…)-Methoden der XXXChangeListener

 
Zum Seitenanfang

4.10.5Change-Klassen Zur vorigen ÜberschriftZur nächsten Überschrift

Drei XXXChangeListener-Schnittstellen haben eine statische innere Klasse, genannt Change, welche genaue Informationen über die Änderungen verrät, also etwa, was hinzukam oder entfernt wurde.

[zB]Beispiel

Fülle eine ObservableMap mit allen Einträgen aus den System-Properties. Mache drei Änderungen, und lass einen Listener die Änderungen protokollieren:

ObservableMap<Object, Object> observableMap = FXCollections.observableMap( System.getProperties() );
MapChangeListener<Object, Object> listener = change -> System.out.println( change );
observableMap.addListener( listener );
observableMap.put( "name", "chris" ); // added chris at key name
observableMap.put( "name", "sha-sha" ); // replaced chris by sha-sha at key name
observableMap.remove( "name" ); // removed sha-sha at key name

Hinter jeder XXXChangeListener.Change-Klasse stehen diverse Abfragemethoden, die uns genau sagen, was passiert ist und was modifiziert und verändert wurde:

Klasse

Methoden

ListChangeListener.Change<E>

boolean wasAdded()
boolean wasPermutated()
boolean wasRemoved()
boolean wasReplaced()
boolean wasUpdated()
int getAddedSize()
List<E> getAddedSubList()
abstract int getFrom()
ObservableList<E> getList()
protected abstract int[] getPermutation()

int getPermutation(int i)
abstract List<E> getRemoved()
int getRemovedSize()
abstract int getTo()
abstract boolean next()
abstract void reset()

SetChangeListener.Change<E>

abstract boolean wasAdded()
abstract boolean wasRemoved()
abstract E getElementAdded()
abstract E getElementRemoved()
ObservableSet<E> getSet()

MapChangeListener.Change<K,V>

abstract boolean wasAdded()
abstract boolean wasRemoved()
abstract K getKey()
ObservableMap<K,V> getMap()
abstract V getValueAdded()
abstract V getValueRemoved()

Tabelle 4.8Abfragemethoden der Change-Ereignis-Klassen

Alle drei Change-Klassen deklarieren eine getXXX()-Methode, die die Datenstruktur selbst wieder hergibt. Das Objekt ListChangeListener.Change verfügt über die meisten Informationen, was ganz einfach daran liegt, dass das Ereignis mehrere geänderte Elemente beschreiben kann, während bei der Menge und dem Assoziativspeicher höchstens eine Veränderung bei einem Element stattfindet. Bei einer Liste kann eine Teilliste komplett hinzukommen – was dann getAddedSubList() erfragbar macht. So etwas ist bei einer Menge oder einem Assoziativspeicher nicht möglich. Hier werden mehrere Elemente auch über mehrere Ereignisse gemeldet.

Während die meisten Methoden durch ihren Namen klar beschrieben sind, gilt das nicht für alle Methoden, insbesondere von ListChangeListener.Change:

  • wasPermutted() zeigt Permutationen an, wie sie bei einer Durchmischung oder Sortierung stattfinden. wasReplaced() zeigt an, dass es eine Ersetzung gab, wasRemoved(), wenn ein Element aus der Liste genommen wurde, und wasAdded() wenn ein Element hinzukam.

  • War die Änderung eine Permutation, so lässt sich eine Schleife bauen der Art for ( int i = change.getFrom(); i < getTo(); i++) und für den Index i mit change.getPermutation(i) bestimmen, wohin ihn die Permutation am Ende verschoben hat; das heißt, dass Element an der Stelle i wanderte an die Stelle change.getPermutation(i).

  • Ein Änderungsereignis kann mehrere Vorgänge repräsentieren. Es gibt wie beim Iterator eine Art Cursor, den next() weitersetzt und reset() zurücksetzt. Es ist so lange ein next() gültig, bis die Rückgabe false() ergibt. Um alle Änderungen abzuarbeiten, ist eine Iteration der Art while ( change.next() ) { … } nötig.

[zB]Beispiel

Die wasXXX()-Methoden müssen in einer speziellen Reihenfolge ausgewertet werden. Am Anfang steht der Test auf Permutation, dann folgt der Test auf Ersetzung, dann Entfernung und zum Schluss Ergänzung. In einem Beispiel wollen wir 1, 2, 3 in eine Liste setzen, dann 1, 3 entfernen und sehen, wie der Durchlauf durch die Änderungen arbeitet:

ObservableList<Integer> list = FXCollections.observableArrayList( 1, 2, 3 );
ListChangeListener<Integer> listener = change -> {
while ( change.next() ) {
if ( change.wasPermutated() )
System.out.println( "permutted" );
else if ( change.wasReplaced() )
System.out.println( "replaced" );
else if ( change.wasRemoved() )
System.out.printf( "removed [%d,%d]%n", change.getFrom(), change.getTo() );
else if ( change.wasAdded() )
System.out.println( "added" );
}
};
list.addListener( listener );
System.out.println( list );
list.removeAll( 1, 3 );
System.out.println( list );

Die Ausgabe ist:

[1, 2, 3]
removed [0,0]
removed [1,1]
[2]

An der zweimaligen Ausgabe von »removed« lässt sich ganz gut der Durchlauf der Schleife ablesen und zudem die Position, die next() beim Change-Objekt verändert.

In den Change-Objekten gibt es viele Informationen, so dass auf diese Weise zwei Sammlungen synchron gehalten werden können: Gibt es in einer beobachteten Liste Änderungen, kann ein eigener XXXChangeListener die durchgeführten Operationen auf eine andere Sammlung spielen und so synchron halten. Meine Leser können als Übung so etwas einmal implementieren.

 
Zum Seitenanfang

4.10.6Weitere Hilfsmethoden einer ObservableList Zur vorigen ÜberschriftZur nächsten Überschrift

Die ObservableXXX-Typen bieten alle die Methoden addListener(…)/removeListener(…), doch ObservableList hat als einzige von den drei Schnittstellen noch ein paar nützliche Extra-Methoden, weil ObservableList in der Praxis – zumindest bei JavaFX-Anwendungen – am häufigsten eingesetzt wird.

interface javafx.collections.ObservableList<E>
extends java.util.List<E>, Observable
  • boolean addAll(E... elements)

  • void remove(int from, int to)

  • boolean removeAll(E... elements)

  • boolean retainAll(E... elements)

  • boolean setAll(Collection<? extends E> col)

  • boolean setAll(E... elements)

Die Hilfsmethoden bieten auf den ersten Blick nichts wirklich Neues, haben aber zwei Vorteile. Erstens sind sie komfortabler, denn ein list.remove(from, to) ist allemal kürzer als list.sublist(from, to).clear(). Der zweite Vorteil der Methoden ist die Anzahl der Änderungen, die sie verschicken. Ein observablelist.addAll(…) wird nur ein Change-Event produzieren, aber ein Collections.addAll(observablelist, …) ist eine Kaskade von add(…)-Aufrufen, was also eine Reihe von Ereignissen nach sich zieht.[ 54 ](Die Implementierung ist: public static <T> boolean addAll(Collection<? super T> c, T... elements) { boolean result = false; for (T element : elements) result |= c.add(element); return result; }) Das Gleiche gilt für setAll(…), was erst löscht und dann hinzufügt, aber nur ein Ereignis auslöst.

Die anderen beiden ObservableXXX-Typen für die java.util-Datenstrukturen bieten bisher keine solche Hilfsmethoden, sondern haben nur die Methoden zum An-/Abmelden der Listener.

 
Zum Seitenanfang

4.10.7Melden von Änderungen an Arrays Zur vorigen ÜberschriftZur nächsten Überschrift

Die Datenstrukturen der Collection-API sind schön über Schnittstellen gekapselt, weshalb es einfach ist, hier einen Stellvertreter mit der gleichen API hinzustellen, der im Hintergrund Ereignisse meldet. Bei Arrays geht das aber nicht, da hier ein Feldzugriff über eine Sprachsyntax gegeben ist und nicht über einen Methodenaufruf. Ein Beobachten von Array-Schreibzugriffen lässt sich also nur über einen neuen Typ realisieren, der genau wie ArrayList Methoden anbietet, die auf die Feldwerte schreiben.

JavaFX bietet änderungsmeldende Arrays für Ganzzahlen vom Typ int und Fließkommazahlen vom Typ float über zwei Hilfstypen ObservableIntegerArray und ObservableFloatArray.

class javafx.collections.FXCollections
  • static ObservableIntegerArray observableIntegerArray()

  • static ObservableIntegerArray observableIntegerArray(int... values)

  • static ObservableIntegerArray observableIntegerArray(ObservableIntegerArray array)

  • static ObservableFloatArray observableFloatArray()

  • static ObservableFloatArray observableFloatArray(float... values)

  • static ObservableFloatArray observableFloatArray(ObservableFloatArray array)

Beide Schnittstellen ObservableIntegerArray und ObservableFloatArray erweitern die Schnittstelle ObservableArray, was gemeinsame Methoden wie das An-/Abmelden von Listenern vorschreibt sowie die Methoden size()und clear(). Die typbezogenen Schnittstellen ObservableIntegerArray und ObservableFloatArray haben die erwarteten Methoden wie get(int index) oder set(int index).

Bei der Ereignisbehandlung sind die Array-Typen etwas einfacher gestrickt, denn es gibt kein Ereignisobjekt. Stattdessen meldet der ArrayChangeListener bei Aufruf von onChanged(T observableArray, boolean sizeChanged, int from, int to) alle Details, mehr Informationen gibt es nicht.

 
Zum Seitenanfang

4.10.8Transformierte FXCollections Zur vorigen ÜberschriftZur nächsten Überschrift

Insbesondere auf grafischen Oberflächen werden Listen von Einträgen oftmals gefiltert oder sortiert dargestellt. Das ist aber in der Regel nur eine Frage der Darstellung, und die darunterliegende Datenstruktur ist natürlich vollständig und unsortiert. Um jetzt bei Änderungen so einer unterliegenden Datenstruktur komfortabel zu einer gefilterten und sortierten Darstellung zu kommen, bietet JavaFX zwei Implementierungen für spezielle ObservableList-Wrapper an: FilteredList und SortedList. Die erste Klasse enthält nur Elemente, die einem Predicate genügen (eine Schnittstelle aus java.util.function), und die zweite Klasse SortedList sortiert nach einem Comparator. FilteredList und SortedList sind selbst auch wieder vom Typ Observable und ObservableList, sodass sie sich problemlos schachteln lassen. Ungewöhnlich ist, dass die Klassen mittels Konstruktor erzeugt werden und nicht über die Fabrikmethoden in FXCollections.

[zB]Beispiel

Eine observableList soll auf dem Bildschirm sortiert dargestellt werden, aber keinen Leer-String enthalten:

ObservableList<String> observableList = FXCollections.observableArrayList();
ObservableList<String> filteredList = new FilteredList<>(
observableList, s -> ! s.isEmpty() );
ObservableList<String> sortedList = new SortedList<>( filteredList, Comparator.naturalOrder() );
observableList.addAll( "", "Hausschwein", "Buttercup" );
System.out.println( sortedList ); // [Buttercup, Hausschwein]

Änderungen an observableList werden nun automatisch weitergeleitet, so dass der Beobachter sortedList diese Veränderung mitbekommt und die Liste neu darstellen kann.

 
Zum Seitenanfang

4.10.9Weitere statische Methoden in FXCollections Zur vorigen ÜberschriftZur nächsten Überschrift

Von FXCollections haben wir bisher die Fabrikmethoden für die ObservableXXX-Typen kennengelernt. Die Klasse bietet aber Hilfsmethoden, die an java.util.Collections angelehnt sind:

class javafx.collections.FXCollections
  • static <E> ObservableList<E> checkedObservableList(ObservableList<E> list, Class<E> type)

  • static <K,V> ObservableMap<K,V> checkedObservableMap(ObservableMap<K,V> map, Class<K> keyType, Class<V> valueType)

  • static <E> ObservableSet<E> checkedObservableSet(ObservableSet<E> set, Class<E> type)

  • static <E> ObservableList<E> concat(ObservableList<E>... lists)

  • static <T> void copy(ObservableList<? super T> dest, List<? extends T> src)

  • static <E> ObservableList<E> emptyObservableList()

  • static <K,V> ObservableMap<K,V> emptyObservableMap()

  • static <E> ObservableSet<E> emptyObservableSet()

  • static <T> void fill(ObservableList<? super T> list, T obj)

  • static <T> boolean replaceAll(ObservableList<T> list, T oldVal, T newVal)

  • static void reverse(ObservableList list)

  • static void rotate(ObservableList list, int distance)

  • static void shuffle(ObservableList<?> list)

  • static void shuffle(ObservableList list, Random rnd)

  • static <E> ObservableList<E> singletonObservableList(E e)

  • static <T extends Comparable<? super T>> void sort(ObservableList<T> list)

  • static <T> void sort(ObservableList<T> list, Comparator<? super T> c)

  • static <E> ObservableList<E> synchronizedObservableList(ObservableList<E> list)

  • static <K,V> ObservableMap<K,V> synchronizedObservableMap(ObservableMap<K,V> map)

  • static <E> ObservableSet<E> synchronizedObservableSet(ObservableSet<E> set)

  • static <E> ObservableList<E> unmodifiableObservableList(ObservableList<E> list)

  • static <K,V> ObservableMap<K,V> unmodifiableObservableMap(ObservableMap<K,V> map)

  • static <E> ObservableSet<E> unmodifiableObservableSet(ObservableSet<E> set)

Die Methoden sind alleine deshalb schon wichtig, weil sie die Anzahl an gemeldeten Änderungen reduzieren. Würde etwa Collections.shuffle(anObservableList) aufgerufen, würde es an Ereignissen nur so rappeln, denn jede Umpositionierung ist ein set(…), und das ist ein Ereignis (zumindest könnte eine Implementierung das so machen). FXCollections.shuffle(anObservableList) führt jedoch zu nur einem Ereignis.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018. Original - https://www.rheinwerk-verlag.de/openbook/
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 

 
 


20.04.2024 - Sitemap.xml