Rheinwerk Computing < openbook >


 
Inhaltsverzeichnis
Materialien
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Arrays und ihre Anwendungen
5 Der Umgang mit Zeichenketten
6 Eigene Klassen schreiben
7 Objektorientierte Beziehungsfragen
8 Ausnahmen müssen sein
9 Geschachtelte Typen
10 Besondere Typen der Java SE
11 Generics<T>
12 Lambda-Ausdrücke und funktionale Programmierung
13 Architektur, Design und angewandte Objektorientierung
14 Java Platform Module System
15 Die Klassenbibliothek
16 Einführung in die nebenläufige Programmierung
17 Einführung in Datenstrukturen und Algorithmen
18 Einführung in grafische Oberflächen
19 Einführung in Dateien und Datenströme
20 Einführung ins Datenbankmanagement mit JDBC
21 Bits und Bytes, Mathematisches und Geld
22 Testen mit JUnit
23 Die Werkzeuge des JDK
A Java SE-Module und Paketübersicht
Stichwortverzeichnis


Download:

- Listings, ca. 2,7 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil17 Einführung in Datenstrukturen und Algorithmen
Pfeil17.1 Listen
Pfeil17.1.1 Erstes Listen-Beispiel
Pfeil17.1.2 Auswahlkriterium ArrayList oder LinkedList
Pfeil17.1.3 Die Schnittstelle List
Pfeil17.1.4 ArrayList
Pfeil17.1.5 LinkedList
Pfeil17.1.6 Der Array-Adapter Arrays.asList(…)
Pfeil17.1.7 ListIterator *
Pfeil17.1.8 toArray(…) von Collection verstehen – die Gefahr einer Falle erkennen
Pfeil17.1.9 Primitive Elemente in Datenstrukturen verwalten
Pfeil17.2 Mengen (Sets)
Pfeil17.2.1 Ein erstes Mengen-Beispiel
Pfeil17.2.2 Methoden der Schnittstelle Set
Pfeil17.2.3 HashSet
Pfeil17.2.4 TreeSet – die sortierte Menge
Pfeil17.2.5 Die Schnittstellen NavigableSet und SortedSet
Pfeil17.2.6 LinkedHashSet
Pfeil17.3 Java Stream-API
Pfeil17.3.1 Deklaratives Programmieren
Pfeil17.3.2 Interne versus externe Iteration
Pfeil17.3.3 Was ist ein Stream?
Pfeil17.4 Einen Stream erzeugen
Pfeil17.4.1 Parallele oder sequenzielle Streams
Pfeil17.5 Terminale Operationen
Pfeil17.5.1 Die Anzahl der Elemente
Pfeil17.5.2 Und jetzt alle – forEachXXX(…)
Pfeil17.5.3 Einzelne Elemente aus dem Strom holen
Pfeil17.5.4 Existenz-Tests mit Prädikaten
Pfeil17.5.5 Einen Strom auf sein kleinstes bzw. größtes Element reduzieren
Pfeil17.5.6 Einen Strom mit eigenen Funktionen reduzieren
Pfeil17.5.7 Ergebnisse in einen Container schreiben, Teil 1: collect(…)
Pfeil17.5.8 Ergebnisse in einen Container schreiben, Teil 2: Collector und Collectors
Pfeil17.5.9 Ergebnisse in einen Container schreiben, Teil 3: Gruppierungen
Pfeil17.5.10 Stream-Elemente in ein Array oder einen Iterator übertragen
Pfeil17.6 Intermediäre Operationen
Pfeil17.6.1 Element-Vorschau
Pfeil17.6.2 Filtern von Elementen
Pfeil17.6.3 Statusbehaftete intermediäre Operationen
Pfeil17.6.4 Präfix-Operation
Pfeil17.6.5 Abbildungen
Pfeil17.7 Zum Weiterlesen
 

Zum Seitenanfang

17.2    Mengen (Sets) Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Menge ist eine (erst einmal) ungeordnete Sammlung von Elementen. Jedes Element darf nur einmal vorkommen. Für Mengen sieht die Java-Bibliothek die Schnittstelle java.util.Set vor. Beliebte implementierende Klassen sind:

  • HashSet: schnelle Mengenimplementierung durch Hashing-Verfahren (Dahinter steckt die HashMap.)

  • TreeSet: Mengen werden durch balancierte Binärbäume realisiert, die eine Sortierung ermöglichen.

  • LinkedHashSet: schnelle Mengenimplementierung unter Beibehaltung der Einfügereihenfolge

  • EnumSet: eine spezielle Menge ausschließlich für Aufzählungen

  • CopyOnWriteArraySet: schnelle Datenstruktur für viele lesende Operationen

 

Zum Seitenanfang

17.2.1    Ein erstes Mengen-Beispiel Zur vorigen ÜberschriftZur nächsten Überschrift

Das folgende Programm analysiert einen Text und erkennt Städte, die vorher in eine Datenstruktur eingetragen wurden. Alle Städte, die im Text vorkommen, werden gesammelt und später ausgegeben.

Listing 17.7    src/main/java/com/tutego/insel/util/set/WhereHaveYouBeen.java

package com.tutego.insel.util.set;



import java.text.BreakIterator;

import java.util.*;



public class WhereHaveYouBeen {

public static void main( String[] args ) {

// Menge mit Städten aufbauen



Set<String> allCities = new HashSet<>();

allCities.add( "Sonsbeck" );

allCities.add( "Düsseldorf" );

allCities.add( "Manila" );

allCities.add( "Seol" );

allCities.add( "Siquijor" );



// Menge für besuchte Städte aufbauen



Set<String> visitedCities = new TreeSet<>();



// Satz parsen und in Wörter zerlegen. Alle gefundenen Städte

// in neue Datenstruktur aufnehmen

String sentence = "Von Sonsbeck fahre ich nach Düsseldorf und fliege nach Manila.";

BreakIterator iter = BreakIterator.getWordInstance();

iter.setText( sentence );



for ( int first = iter.first(), last = iter.next();

last != BreakIterator.DONE;

first = last, last = iter.next() ) {

String word = sentence.substring( first, last );

if ( allCities.contains( word ) )

visitedCities.add( word );

}



// Kleine Statistik



System.out.println( "Anzahl besuchter Städte: " + visitedCities.size() );

System.out.println( "Anzahl nicht besuchter Städte: " +

(allCities.size() - visitedCities.size()) );

System.out.println( "Besuchte Städte: " + String.join( ", ", visitedCities ) );

Set<String> unvisitedCities = new TreeSet<>( allCities );

unvisitedCities.removeAll( visitedCities );

System.out.println( "Unbesuchte Städte: " + String.join( ", ", unvisitedCities ) );

}

}

Insgesamt kommen drei Mengen im Programm vor:

  • allCities speichert alle möglichen Städte. Die Wahl fällt auf den Typ HashSet, da die Menge nicht sortiert sein muss, Nebenläufigkeit kein Thema ist und HashSet eine gute Zugriffszeit bietet.

  • Ein TreeSet visitedCities merkt sich die besuchten Städte. Auch dieses Set ist schnell, hat aber den Vorteil, dass es die Elemente sortiert hält. Das ist später hübsch in der Ausgabe.

  • Um alle nicht besuchten Städte herauszufinden, berechnet das Programm die Differenzmenge zwischen allen Städten und besuchten Städten. Es gibt in der Schnittstelle Set keine Methode, die das direkt macht – genau genommen gibt es keine Operation in Set, die den Rückgabetyp Set oder Collection hat. Also können wir nur mit einer Methode wie removeAll(…) arbeiten, die aus der Menge aller Städte die besuchten entfernt, um zu denen zu kommen, die noch nicht besucht wurden. Das »Problem« der removeAll(…)-Methode ist aber ihre zerstörerische Art – die Elemente werden aus der Menge gelöscht. Da die Originalmenge jedoch nicht verändert werden soll, kopieren wir alle Städte in einen Zwischenspeicher (unvisitedCities) und löschen aus diesem Zwischenspeicher, was die Originalmenge unangetastet lässt.

[»]  Hinweis

Auch reguläre Ausdrücke wären eine Option zum Zerlegen von Sätzen und kommen an anderen Stellen im Buch auch vor. Allerdings hat der BreakIterator den Vorteil, dass er jedes einzelne Unicode-Zeichen korrekt einordnen kann.

 

Zum Seitenanfang

17.2.2    Methoden der Schnittstelle Set Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Mengenklasse deklariert neben Operationen für die Anfrage und das Einfügen von Elementen auch Methoden für den Schnitt und die Vereinigung von Mengen.

interface java.util.Set<E>

extends Collection<E>
  • boolean add(E o)

    Setzt o in die Menge, falls dort noch kein equals-gleiches Objekt vorliegt. Liefert true bei erfolgreichem Einfügen.

  • boolean addAll(Collection<? extends E> c)

    Fügt alle Elemente von c in das Set ein. Ist c ein anderes Set, so steht addAll(…) für die Mengenvereinigung. Im Kern ist das ein for (E e : c) add(e);. Die Rückgabe ist true, wenn sich die Sammlung in irgendeiner Weise verändert hat.

  • void clear()

    Löscht das Set.

  • boolean contains(Object o)

    Ist das Element o in der Menge?

  • boolean containsAll(Collection<?> c)

    Ist c eine Teilmenge von Set?

  • static <E> Set<E> copyOf (Collection<? extends E> coll)

    Erzeugt eine unmodifizierbare Kopie. Neu in Java 10.

  • boolean isEmpty()

    Ist das Set leer?

  • Iterator<E> iterator()

    Gibt einen Iterator für das Set zurück.

  • boolean remove(Object o)

    Löscht o aus dem Set, liefert true bei erfolgreichem Löschen, andernfalls false, wenn es kein equals-gleiches Objekt in der Menge gab.

  • boolean removeAll(Collection<?> c)

    Löscht alle Elemente der Collection aus dem Set und liefert true bei erfolgreichem Löschen.

  • boolean retainAll(Collection<?> c)

    Die Menge behält (engl. retains) alle Elemente, die auch in c sind. Anders gesagt: Alle Elemente der eigenen Menge werden gelöscht, die nicht auch in c vorhanden sind. An der Datenstruktur c gibt es keine Änderung. Die eigene Menge ist dann die Schnittmenge mit c, aber c kann noch viel mehr Elemente enthalten.

  • int size()

    Gibt die Anzahl der Elemente in der Menge zurück.

  • Object[] toArray()

    Erzeugt zunächst ein neues Array, in dem alle Elemente der Menge Platz finden, und kopiert anschließend die Elemente in das Array.

  • <T> T[] toArray(T[] a)

    Ist das übergebene Array groß genug für alle Elemente der Menge, dann werden alle Elemente der Menge in das Array kopiert und a zurückgegeben. Ist das Array zu klein, wird ein neues Array vom Typ T angelegt, und alle Elemente werden von der Menge in das Array kopiert und zurückgegeben.

  • default <T> T[] toArray(IntFunction<T[]> generator)

    Wie in Collection dokumentiert.

In der Schnittstelle Set werden die aus Object stammenden Methoden equals(…) und hashCode() mit ihrer Funktionalität bei Mengen in der API-Dokumentation präzisiert.

[»]  Hinweis

In einem Set gespeicherte Elemente müssen immutable bleiben. Einerseits sind sie nach einer Änderung vielleicht nicht wiederzufinden, andererseits können Elemente auf diese Weise doppelt in der Menge vorkommen, was der Philosophie der Schnittstelle widerspricht.

Ein Element erneut hinzunehmen

Ist ein Element in der Menge noch nicht vorhanden, fügt add(…) es ein und liefert als Rückgabe true. Ist es schon vorhanden, macht add(…) nichts und liefert false. (Das ist bei einer Map anders, denn dort überschreibt put(…) den Schlüssel.) Ob ein hinzuzufügendes Element mit einem existierenden in der Menge übereinstimmt, bestimmt die equals(…)-Methode, also die Gleichwertigkeit und nicht die Identität:

Listing 17.8    src/main/java/com/tutego/insel/util/set/HashSetDoubleAdd.java, main()

Set<Point> set = new HashSet<>();

Point p1 = new Point(), p2 = new Point();

System.out.println( set.add(p1) ); // true

System.out.println( set.add(p1) ); // false

System.out.println( set.add(p2) ); // false

System.out.println( set.contains(p1) ); // true

System.out.println( set.contains(p2) ); // true
 

Zum Seitenanfang

17.2.3    HashSet Zur vorigen ÜberschriftZur nächsten Überschrift

Ein java.util.HashSet verwaltet die Elemente in einer schnellen hashbasierten Datenstruktur. Dadurch sind die Elemente schnell einsortiert und schnell zu finden. Falls eine Sortierung der Elemente vom HashSet nötig ist, müssen die Elemente zum Beispiel in eine List oder ein TreeSet umkopiert und dann sortiert werden.

class java.util.HashSet<E>

extends AbstractSet<E>

implements Set<E>, Cloneable, Serializable
  • HashSet()

    Erzeugt ein leeres HashSet-Objekt.

  • HashSet(Collection<? extends E> c)

    Erzeugt aus der Sammlung c ein neues unsortiertes HashSet.

  • HashSet(int initialCapacity)

  • HashSet(int initialCapacity, float loadFactor)

    Die beiden Konstruktoren sind zur Optimierung gedacht – HashSet basiert intern auf der HashMap.

 

Zum Seitenanfang

17.2.4    TreeSet – die sortierte Menge Zur vorigen ÜberschriftZur nächsten Überschrift

Die Klasse java.util.TreeSet implementiert ebenfalls wie HashSet die Set-Schnittstelle, verfolgt aber eine andere Implementierungsstrategie. Ein TreeSet verwaltet die Elemente immer sortiert (intern werden die Elemente in einem balancierten Binärbaum gehalten). Speichert TreeSet ein neues Element, so fügt TreeSet das Element automatisch sortiert in die Datenstruktur ein. Das kostet zwar etwas mehr Zeit als ein HashSet, doch ist diese Sortierung dauerhaft. Daher ist es auch nicht zeitaufwendig, alle Elemente geordnet auszugeben. Die Suche nach einem einzigen Element ist aber etwas langsamer als im HashSet. Der Begriff »langsamer« muss jedoch relativiert werden: Die Suche ist logarithmisch und daher nicht wirklich »langsam«. Beim Einfügen und Löschen muss bei bestimmten Konstellationen eine Reorganisation des Baums in Kauf genommen werden, was die Einfüge- bzw. Löschzeit verschlechtert. Doch auch beim Re-Hashing gibt es diese Kosten, die sich dort jedoch durch die passende Startgröße vermeiden lassen.

class java.util.TreeSet<E>

extends AbstractSet<E>

implements NavigableSet<E>, Cloneable, Serializable
  • TreeSet()

    Erzeugt ein neues, leeres TreeSet.

  • TreeSet(Collection<? extends E> c)

    Erzeugt ein neues TreeSet aus der gegebenen Collection.

  • TreeSet(Comparator<? super E> c)

    Erzeugt ein leeres TreeSet mit einem gegebenen Comparator, der für die Sortierung der internen Datenstruktur die Vergleiche übernimmt.

  • TreeSet(SortedSet<E> s)

    Erzeugt ein neues TreeSet und übernimmt alle Elemente von s und auch die Sortierung von s. (Einen Konstruktor mit NavigableSet gibt es nicht.)

[zB]  Beispiel

Teste, ob eine Liste von Datumswerten, die nur einmal in der Liste vorkommen dürfen, aufsteigend sortiert ist:

List<Instant> dates = Arrays.asList( Instant.ofEpochMilli( 2L ),

Instant.ofEpochMilli( 3L ) );

boolean isSorted = new ArrayList<>( new TreeSet<>( dates ) ).equals( dates );

Nimmt der Konstruktor von TreeSet eine andere Sammlung entgegen, so entsteht eine sortierte Sammlung aller Elemente. Diese Sammlung kann wiederum in einen anderen Konstruktor gegeben werden, der Collection-Objekte annimmt, wie zum Beispiel eine ArrayList. Unser Beispiel vergleicht zwei List-Exemplare mit equals(…), wobei Listen eine Ordnung haben. Stimmt die Ordnung nach dem Sortieren mit der vor der Sortierung überein, war die Liste schon sortiert.

Natürlich gibt es bessere Implementierungen. Zum Beispiel könnte man mit einem Iterator die Sammlung ablaufen und schauen, ob das nächste Element immer größer oder gleich ist.

Bedeutung der Sortierung

Durch die interne sortierte Speicherung gibt es zwei ganz wichtige Bedingungen:

  • Die Elemente müssen sich vergleichen lassen. Kommen zum Beispiel Player-Objekte in das TreeSet, aber implementiert Player nicht die Schnittstelle Comparable, löst TreeSet eine Ausnahme aus, da TreeSet nicht weiß, in welcher Reihenfolge die Spieler stehen.

  • Die Elemente müssen vom gleichen Typ sein. Wie sollte sich ein Kirchen-Objekt mit einem Staubsauger-Objekt vergleichen lassen?

[zB]  Beispiel

Sortiere Strings in eine Menge ein, wobei die Groß-/Kleinschreibung und vorangestellter bzw. nachfolgender Weißraum keine Rolle spielen. Anders gesagt: Wörter sollen auch dann als gleich angesehen werden, wenn sie sich in der Groß-/Kleinschreibweise unterscheiden oder etwa Weißraum am Anfang und Ende besitzen:

Comparator<String> comparator = (s1, s2) -> String.CASE_INSENSITIVE_ORDER.compare( s1.trim(), s2.trim() );

Set<String> set = new TreeSet<>( comparator );

Collections.addAll( set, "xxx ", " XXX", "tang", " xXx", " QUEEF " );

System.out.println( set ); // [ QUEEF , tang, xxx ]

Die Methode equals(…) und die Vergleichsmethoden

Die Methode equals(…) spielt für Datenstrukturen eine große Rolle. Beim TreeSet ist das anders, denn es nutzt zur Einordnung einen externen Comparator bzw. die compareTo(…)-Eigenschaft, wenn die Elemente Comparable sind. Gibt die Vergleichsmethode 0 zurück, so sind die Elemente gleich, und gleiche Elemente sind in der Menge nicht erlaubt. equals(…) wird dabei nicht gefragt, wenngleich natürlich die equals-Implementierung true liefern sollte, wenn compare(…) bzw. compareTo(…) 0 liefert.

Nehmen wir als Beispiel den Comparator aus dem vorangegangenen Beispiel für String-Objekte, der unabhängig von der Groß-/Kleinschreibung und Weißraum vergleicht. Dann sind laut equals(…) die Strings "xxx " und " XXX" sicherlich nicht gleich, der Comparator würde aber Gleichwertigkeit anzeigen. Dies führt dazu, dass tatsächlich nur eines der beiden Objekte in das TreeSet kommt und eine Anfrage nach einem Comparator-gleichen Objekt daher das Element liefert:

Comparator<String> comparator = (s1, s2) -> String.CASE_INSENSITIVE_ORDER.compare( s1.trim(), s2.trim() );

Set<String> set = new TreeSet<>( comparator );
 

Zum Seitenanfang

17.2.5    Die Schnittstellen NavigableSet und SortedSet Zur vorigen ÜberschriftZur nächsten Überschrift

TreeSet implementiert die Schnittstelle NavigableSet und bietet darüber Methoden, die insbesondere zu einem gegebenen Element das nächsthöhere bzw. nächstkleinere liefern. Somit sind auf Mengen nicht nur die üblichen Abfragen über Mengenzugehörigkeit denkbar, sondern auch Abfragen wie »Gib mir das Element, das größer oder gleich einem gegebenen Element ist«.

Folgendes Beispiel reiht in ein TreeSet drei LocalDate-Objekte ein. Die Klasse LocalDate implementiert Comparable<LocalDate>, denn die Objekte haben eine natürliche Ordnung. Die Methoden lower(…), ceiling(…), floor(…) und higher(…) wählen aus der Menge das angefragte Objekt aus:

Listing 17.9    src/main/java/com/tutego/insel/util/set/SortedSetDemo.java

NavigableSet<LocalDate> set = new TreeSet<>();

set.add( LocalDate.of( 2018, Month.MARCH, 10 ) );

set.add( LocalDate.of( 2018, Month.MARCH, 12 ) );

set.add( LocalDate.of( 2018, Month.MARCH, 14 ) );



LocalDate cal1 = set.lower( LocalDate.of( 2018, Month.MARCH, 12 ) );

System.out.printf( "%tF%n", cal1 ); // 2018-03-10



LocalDate cal2 = set.ceiling( LocalDate.of( 2018, Month.MARCH, 12 ) );

System.out.printf( "%tF%n", cal2 ); // 2018-03-12



LocalDate cal3 = set.floor( LocalDate.of( 2018, Month.MARCH, 12 ) );

System.out.printf( "%tF%n", cal3 ); // 2018-03-12



LocalDate cal4 = set.higher( LocalDate.of( 2018, Month.MARCH, 12 ) );

System.out.printf( "%tF%n", cal4 ); // 2018-03-14

Eine Methode wie tailSet(…) ist insbesondere bei Datumsobjekten sehr praktisch, da sie alle Zeitpunkte liefern kann, die nach einem Startdatum liegen.

TreeSet implementiert die Schnittstelle NavigableSet, die ihrerseits SortedSet erweitert – ein historisches Erbe. Insgesamt bietet NavigableSet 15 Operationen, wobei sie aus SortedSet die Methoden headSet(…), tailSet(…) und subSet(…) um die überladene Version der Methoden ergänzt, die die Grenzen exklusiv oder inklusiv erlauben.

interface java.util.NavigableSet<E>

extends SortedSet<E>
  • NavigableSet<E> headSet(E toElement)

  • NavigableSet<E> tailSet(E fromElement)

    Liefern eine Teilmenge von Elementen, die echt kleiner/größer als toElement/fromElement sind.

  • NavigableSet<E> headSet(E toElement, boolean inclusive)

  • NavigableSet<E> tailSet(E fromElement, boolean inclusive)

    Bestimmen gegenüber den oberen Methoden zusätzlich, ob das Ausgangselement zur Ergebnismenge gehören darf.

  • NavigableSet<E> subSet(E fromElement, E toElement)

    Liefert eine Teilmenge im gewünschten Bereich.

  • E pollFirst()

  • E pollLast()

    Holt und entfernt das erste bzw. letzte Element. Die Rückgabe ist null, wenn das Set leer ist.

  • E higher(E e)

  • E lower(E e)

    Liefert das folgende bzw. vorangehende Element im Set, das echt größer bzw. kleiner als E ist, oder null, falls ein solches Element nicht existiert.

  • E ceiling(E e)

  • E floor(E e)

    Liefert das folgende bzw. vorangehende Element im Set, das größer bzw. kleiner oder gleich E ist, oder null, falls ein solches Element nicht existiert.

  • Iterator<E> descendingIterator()

    Liefert die Elemente in umgekehrter Reihenfolge.

Aus der Schnittstelle SortedSet erbt NavigableSet im Grunde nur drei Operationen, denn subSet(…), headSet(…) und tailSet(…) werden mit kovariantem Rückgabetyp in NavigableSet redefiniert.

interface java.util.SortedSet<E>

extends Set<E>
  • E first()

    Liefert das kleinste Element in der Liste.

  • E last()

    Liefert das größte Element.

  • Comparator<? super E> comparator()

    Liefert den mit der Menge verbundenen Comparator. Die Rückgabe kann null sein, wenn sich die Objekte mit Comparable selbst vergleichen können.

  • SortedSet<E> subSet(E fromElement, E toElement)

  • SortedSet<E> headSet(E toElement)

  • SortedSet<E> tailSet(E fromElement)

    Liefert Teilmengen als live-Sichten.

Anders als HashSet liefert der Iterator beim TreeSet die Elemente aufsteigend sortiert. Davon profitieren auch die beiden toArray(…)-Methoden – implementiert in AbstractCollection –, da sie den Iterator nutzen, um ein sortiertes Array zurückzugeben.

[zB]  Beispiel

Eine Variable contacts ist vom Typ Map<Long,String> und assoziiert IDs vom Typ long mit Strings. Ein neuer Kontakt soll eine ID bekommen, die um 1 höher ist als die höchste ID des Assoziativspeichers:

contact.setId( new TreeSet<Long>( contacts.keySet() ).last() + 1L );
 

Zum Seitenanfang

17.2.6    LinkedHashSet Zur vorigen ÜberschriftZur nächsten Überschrift

Ein LinkedHashSet vereint die Reihenfolgetreue einer Liste mit der hohen Performance für Mengenoperationen des HashSets. Dabei bietet die Klasse keine Listen-Methoden wie first() oder get(int index), sondern ist eine Implementierung ausschließlich der Set-Schnittstelle, in der der Iterator die Elemente in der Einfügereihenfolge liefert:

Listing 17.10    src/main/java/com/tutego/insel/util/set/LinkedHashSetDemo.java, main()

Set<Integer> set = new LinkedHashSet<>(

Arrays.asList( 9, 8, 7, 6, 9, 8 )

);



for ( Integer i : set )

System.out.print( i + " " ); // 9 8 7 6



System.out.printf( "%n%s", set ); // [9, 8, 7, 6]

Da ein Set jedes Element nur einmal beinhalten kann, bekommen wir als Ergebnis jedes Element nur einmal, aber gleichzeitig geht die Reihenfolge des Einfügens nicht verloren. Der Iterator liefert die Elemente genau in der Einfügereihenfolge.

[zB]  Beispiel

Dass ein LinkedHashSet eine Menge ist, die Elemente nur einmal enthält, sich aber beim Einfügen wie eine Liste verhält, ist nützlich, um doppelte Elemente aus einer Liste zu löschen:

public static <T> List<T> removeDuplicate( List<T> list ) {

return new ArrayList<>( new LinkedHashSet<>( list ) );

}

Das Ergebnis ist eine neue Liste, und list selbst wird nicht modifiziert. Zum Beispiel ergibt removeDuplicate( Arrays.asList( 1,2,1,3,1,2,4 ) ) die Liste [1, 2, 3, 4].

LinkedHashSet und Iterator

Mit einem Iterator lässt sich jedes Element von LinkedHashSet nach der Reihenfolge des Einfügens auflisten. Der Iterator von LinkedHashSet unterstützt auch die remove()-Methode. Sie kann eingesetzt werden, um die ältesten Einträge zu löschen und nur noch die neuesten zwei Elemente beizubehalten:

LinkedHashSet<Integer> set = new LinkedHashSet<>();

set.addAll( Arrays.asList( 3, 2, 1, 6, 5, 4 ) );

System.out.println( set ); // [3, 2, 1, 6, 5, 4]

for ( Iterator<Integer> iter = set.iterator(); iter.hasNext(); ) {

iter.next();

if ( set.size() > 2 )

iter.remove();

}

System.out.println( set ); // [5, 4]

 


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 ist auch eine Insel Java ist auch eine Insel

Jetzt Buch bestellen


 Buchempfehlungen
Zum Rheinwerk-Shop: Captain CiaoCiao erobert Java

Captain CiaoCiao erobert Java




Zum Rheinwerk-Shop: Java SE 9 Standard-Bibliothek

Java SE 9 Standard-Bibliothek




Zum Rheinwerk-Shop: Algorithmen in Java

Algorithmen in Java




Zum Rheinwerk-Shop: Objektorientierte Programmierung

Objektorientierte Programmierung




 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2021

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.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de



Cookie-Einstellungen ändern