HashMaps und Collections in Java

Lerne, Daten mit HashMap über Schlüssel zu speichern und abzurufen, Werte zu zählen und zu gruppieren sowie mit HashSet Werte ohne Duplikate zu verwalten. Erfahre, was die Interfaces List, Set und Map garantieren, sortiere Listen, gib deinen eigenen Klassen mit Comparable eine natürliche Ordnung und wähle für jede Aufgabe die passende Collection.

AnfängerEinheit 7 von 11 in Kurs: Java-Programmierung – Klassen, Vererbung, Collections und Streams

Was du lernst

  1. Erstelle HashMaps, füge Schlüssel-Wert-Paare hinzu, lies, ändere und entferne sie, durchlaufe die Inhalte einer Map und verwende eigene Klassen als Schlüssel, die die Map wiederfinden kann.
    • Erstelle eine HashMap, füge Einträge ein, rufe sie ab, ändere und entferne sie
      Deklariere eine HashMap mit Schlüssel- und Werttyp, speichere Paare mit put, lies sie mit get und behandle fehlende Schlüssel.
    • Durchlaufe Schlüssel, Werte und Einträge mit Schleifen
      Durchlaufe jedes Paar einer Map mit keySet, values und entrySet, erkenne die zu erwartende Reihenfolge und ändere eine Map während einer Schleife sicher.
    • Verwende eigene Objekte als Map-Schlüssel
      Sorge dafür, dass Objekte eigener Klassen als Schlüssel funktionieren, indem du equals und hashCode gemeinsam überschreibst, und ändere Schlüssel nicht, während sie in einer Map stehen.
  2. Verwende Maps, um Vorkommen zu zählen, zusammengehörige Werte unter einem Schlüssel zu sammeln und Nachschlagetabellen für den schnellen Zugriff auf Objekte zu erstellen.
    • Zähle Vorkommen und berechne Summen je Schlüssel
      Erstelle Häufigkeitstabellen und laufende Summen mit dem getOrDefault-Muster und lies die Ergebnisse richtig.
    • Gruppiere Werte unter einem Schlüssel und verwende Listen und Mengen als Map-Werte
      Erstelle Maps, deren Werte Listen oder Mengen sind, füge Elemente zur richtigen Gruppe hinzu und vermeide Fehler, durch die Gruppen verloren gehen oder beschädigt werden.
    • Rufe Objekte und Preise mit einem auf einer Map basierenden Suchindex schnell ab
      Verwende Maps als Nachschlagetabellen und Suchindizes, die Objekte über einen eindeutigen Schlüssel finden, verwalte sie innerhalb einer Klasse und halte mehrere Suchindizes konsistent.
  3. Verwende HashSet, um Werte ohne Duplikate zu speichern, die Mengenzugehörigkeit schnell zu prüfen und Mengen durch Vereinigung, Schnitt und Differenz zu verknüpfen.
    • Speichere Werte ohne Duplikate und prüfe ihre Mengenzugehörigkeit mit HashSet
      Füge Werte in einem HashSet hinzu, prüfe und entferne sie, verwende das Ergebnis von add und entferne Duplikate aus einer Liste.
    • Verknüpfe Mengen und verwalte ihre Reihenfolge
      Berechne Vereinigungsmengen, Schnittmengen und Differenzmengen, ohne die ursprünglichen Mengen zu verändern, vergleiche Mengen und wähle eine geordnete Menge, wenn die Reihenfolge wichtig ist.
  4. Deklariere Collections mit ihren Interface-Typen, verstehe die Garantien jedes Interfaces und verwende die gemeinsamen Methoden, die über Implementierungen hinweg funktionieren.
    • Deklariere Variablen und Parameter mit Interface-Typen
      Erkläre, was ein Interface-Typ ist, deklariere Collections als List, Set oder Map und schreibe Methoden, die jede Implementierung annehmen.
    • Verstehe die Garantien von List, Set und Map
      Vergleiche die Garantien der drei Interfaces, erkenne ihre wichtigsten Implementierungen und arbeite mit nicht modifizierbaren Collections, die mit of erzeugt werden.
  5. Sortiere Listen in natürlicher Ordnung, gib deinen eigenen Klassen durch die Implementierung von Comparable eine natürliche Ordnung und verwende diese Ordnung in sortierten Mengen und Maps.
    • Sortiere Listen mit Zahlen und Strings
      Sortiere eine Liste mit Collections.sort direkt, sage die Reihenfolge von Strings voraus und sortiere umgekehrt oder ohne Beachtung der Groß- und Kleinschreibung.
    • Implementiere Comparable in einer eigenen Klasse
      Gib einer Klasse eine natürliche Ordnung, indem du Comparable implementierst und compareTo mit sicheren Vergleichen für Zahlen und Strings schreibst.
    • Löse Gleichstände mit weiteren Vergleichskriterien auf und verwende sortierte Mengen und Maps
      Ordne Objekte nach mehreren Feldern, halte compareTo konsistent mit equals und verwende TreeSet und TreeMap, um Daten sortiert zu halten.
  6. Vergleiche die Geschwindigkeit gängiger Operationen in den einzelnen Collections und wähle den Typ, der zu den Aufgaben des Programms mit seinen Daten passt.
    • Vergleiche den Aufwand gängiger Collection-Operationen
      Schätze ab, wie die Laufzeit von Zugriffen, Einfügungen und Entfernungen mit der Größe der jeweiligen Collection wächst, und erkenne langsame Muster.
    • Wähle eine Collection, die zur Aufgabe passt
      Beantworte einige Fragen zu Reihenfolge, Duplikaten und Zugriff, um zwischen Arrays, Listen, Mengen und Maps zu wählen, und kombiniere sie für komplexere Daten.

HashMaps und Collections in Java einfach erklärt

6 Kapitel

1

Speichere Daten mit HashMap und rufe sie über Schlüssel ab

Ein Produktcode kann direkt zu einer Bestandsmenge führen, ohne eine Liste zu durchsuchen. Maps stellen diese Zuordnung ausdrücklich her. Um sie gut zu nutzen, musst du außerdem fehlende Schlüssel behandeln, Paare sicher durchlaufen und festlegen, wann zwei Schlüsselobjekte als gleich gelten. Beginne mit einer kleinen Bestands-Map und verfolge dann, wie sich ihr Inhalt ändert und wie Java einen gespeicherten Schlüssel wiederfindet. Dieselben Gleichheitsregeln sind später auch bei Mengen wichtig.

1.1 Erstelle eine HashMap, füge Einträge ein, rufe sie ab, ändere und entferne sie

Eine Map speichert die Zuordnung jedes Schlüssels zu einem Wert. In einer Bestands-Map ist ein Produktname der Schlüssel und seine Anzahl der Wert. Zwei Produkte können dieselbe Anzahl haben, aber ein Produktschlüssel kann nicht zwei separate Einträge enthalten.

Erstelle die Map
import java.util.HashMap;

HashMap<String, Integer> stock = new HashMap<>();

Der erste Typ, String, beschreibt die Schlüssel. Der zweite, Integer, beschreibt die Werte. Der Diamant <> rechts lässt Java diese Typen ableiten. Typargumente müssen Referenztypen sein: Verwende Integer, Double, Character oder Boolean statt int, double, char oder boolean. Java wandelt einen einfachen int beim Speichern in einen Integer um und einen Integer zurück, wenn ein int gebraucht wird.

Verfolge jede Änderung
stock.put("apple", 12);
stock.put("pear", 7);
Integer previous = stock.put("apple", 15);

Der erste Aufruf erzeugt apple=12; der zweite fügt pear=7 hinzu. Der dritte findet den vorhandenen Schlüssel "apple" und ersetzt seinen Wert. Die Map hat nun zwei Einträge, und previous enthält 12. Ein put für einen Schlüssel ohne bisherige Zuordnung gibt null zurück.

stock.get("apple") liefert nun 15. stock.remove("pear") liefert 7 und entfernt diesen Eintrag. Ein erneutes Entfernen von "pear" liefert null. size() zählt die Einträge, isEmpty() prüft, ob keine vorhanden sind, und clear() entfernt alle Einträge.

Behandle einen fehlenden Schlüssel

stock.get("kiwi") liefert null, und stock.containsKey("kiwi") liefert false. Diese Anweisung lässt sich kompilieren, schlägt aber bei der Ausführung fehl:

int quantity = stock.get("kiwi");

Java versucht, null per Unboxing in einen int umzuwandeln, und löst dadurch eine NullPointerException aus. Verwende für eine Map mit Mengenangaben, die nicht null sind, einen Standardwert:

int quantity = stock.getOrDefault("kiwi", 0);

Das ergibt 0, ohne "kiwi" zur Map hinzuzufügen. Du kannst auch vor dem Lesen containsKey prüfen. containsValue(15) fragt, ob irgendein Eintrag diesen Wert hat; dabei werden möglicherweise alle Werte durchsucht. Das unterscheidet sich vom Zugriff über einen bekannten Schlüssel.

Eine HashMap erlaubt auch einen null-Schlüssel und null-Werte. Ist einem Schlüssel ausdrücklich null zugeordnet, gibt getOrDefault das gespeicherte null zurück, nicht den Standardwert. containsKey unterscheidet diesen Fall von einem fehlenden Schlüssel. Maps für Mengenangaben sind einfacher, wenn jede gespeicherte Angabe eine tatsächliche Zahl ist.

Vergleiche Schlüssel und Werte richtig

Bei String-Schlüsseln wird die Groß- und Kleinschreibung beachtet: "apple", "Apple" und "apple " sind verschieden. Wende vor dem Speichern und Suchen dieselbe Bereinigung an, etwa name.trim().toLowerCase(). Nur einen Suchschlüssel zu bereinigen, kann uneinheitlich gespeicherte Schlüssel nicht korrigieren.

Vergleiche Werte von Wrapperobjekten mit equals anhand ihres Inhalts. Enthalten zwei Einträge jeweils 1000, können ihre Integer-Referenzen verschieden sein, sodass == falsch sein kann, obwohl ihre numerischen Inhalte übereinstimmen. Nachdem du geprüft hast, dass beide Werte nicht null sind, vergleicht a.equals(b) ihre Inhalte.

Wichtige Erkenntnisse

  • Jeder eindeutige Schlüssel ist einem Wert zugeordnet; Werte dürfen mehrfach vorkommen.
  • put ersetzt einen vorhandenen Wert und gibt den vorherigen Wert zurück.
  • Ein get für einen fehlenden Schlüssel liefert null; das Unboxing löst eine NullPointerException aus.
  • getOrDefault liefert nur bei einem fehlenden Schlüssel einen Standardwert.
  • Vergleiche String-Schlüssel einheitlich und Werte von Wrapperobjekten anhand ihres Inhalts.

1.2 Durchlaufe Schlüssel, Werte und Einträge mit Schleifen

Eine Map kann einen einzelnen Wert liefern oder alle ihre Daten für eine Schleife bereitstellen. Wähle die Sicht, die die benötigten Teile liefert. Die Sichten sind mit der Map verbunden, sodass Änderungen über sie auch die Map ändern können.

Wähle Schlüssel, Werte oder Einträge

Verwende keySet(), um Schlüssel zu durchlaufen. Ein Zugriff innerhalb dieser Schleife kann den jeweiligen Wert abrufen:

for (String name : phoneBook.keySet()) {
    System.out.println(name + ": " + phoneBook.get(name));
}

Verwende values(), wenn die Schlüssel keine Rolle spielen. Für die Bestandsmengen apple 15, pear 7 und fig 3:

int total = 0;
for (int quantity : stock.values()) {
    total += quantity;
}

Die Summe wird 25. Wiederholte Werte tragen weiterhin einzeln zur Summe bei: Eine Wertesicht ist keine Menge.

Ein Eintrag enthält einen Schlüssel und seinen Wert zusammen. Importiere java.util.Map und verwende Map.Entry<K, V> mit getKey() und getValue(). Das vermeidet einen zweiten Zugriff:

String best = null;
int bestScore = Integer.MIN_VALUE;
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    if (best == null || entry.getValue() > bestScore) {
        best = entry.getKey();
        bestScore = entry.getValue();
    }
}

Für Ana 82, Ben 91 und Cai 77 ist das Ergebnis Ben mit 91. Die Prüfung best == null behandelt auch den Fall, dass die erste Punktzahl dem kleinstmöglichen int entspricht. Bei einer leeren Map bleibt best gleich null.

Wähle die Reihenfolge ausdrücklich

Eine HashMap garantiert keine Iterationsreihenfolge. Du kannst weder von der Einfügereihenfolge noch von einer sortierten Reihenfolge oder der heute ausgegebenen Reihenfolge ausgehen. Eine LinkedHashMap behält die Einfügereihenfolge bei; eine TreeMap besucht sortierte Schlüssel. Haben zwei Personen dieselbe Punktzahl, behält die Schleife oben die zuerst besuchte. Bei einer HashMap könnte jeder der beiden Namen gewinnen. Ergänze eine ausdrückliche Regel für Gleichstände, wenn das Ergebnis vorhersagbar sein muss.

Entferne Einträge über den Iterator

Der Aufruf von stock.remove(key) innerhalb einer for-each-Schleife über stock.keySet() ändert die Schlüssel, die die Schleife durchläuft. Das kann eine ConcurrentModificationException auslösen. Die Erkennung ist nicht garantiert; ein Durchlauf ohne Ausnahme macht dieses Muster nicht zulässig.

Verwende die eigene Entfernungsmethode des Iterators:

Iterator<Map.Entry<String, Integer>> it =
    stock.entrySet().iterator();
while (it.hasNext()) {
    if (it.next().getValue() == 0) {
        it.remove();
    }
}

Importiere java.util.Iterator. Bei apple 15, pear 0, fig 0 und kiwi 4 werden so pear und fig entfernt. Eine weitere sichere Möglichkeit ist, Schlüssel in einer Liste zu sammeln, die Schleife abzuschließen und die Schlüssel danach zu entfernen.

Das Ersetzen eines vorhandenen Werts fügt keinen Schlüssel hinzu und entfernt keinen. Während einer Schleife über Einträge kann entry.setValue(entry.getValue() * 2) die Mengen sicher verdoppeln. Füge während dieser Schleife keine neuen Schlüssel über die Map hinzu.

Unterscheide eine Sicht von einer Kopie

stock.keySet().remove("apple") entfernt den zugehörigen Map-Eintrag. Eine mit new ArrayList<>(stock.keySet()) erzeugte separate Liste ist eine Kopie der aktuellen Schlüssel. Das Sortieren dieser Liste ändert die Reihenfolge der Map nicht, und das Entfernen eines Namens aus der Liste entfernt seine Zuordnung nicht.

Wichtige Erkenntnisse

  • Verwende je nach Bedarf der Schleife keySet, values oder entrySet.
  • HashMap hat keine garantierte Iterationsreihenfolge; löse Gleichstände ausdrücklich auf.
  • Verwende das remove eines Iterators, um während der Traversierung zu löschen.
  • Das Ersetzen eines vorhandenen Werts ist während der Traversierung erlaubt.
  • Map-Sichten sind mit der Map verbunden; eine kopierte Schlüsselliste ist eigenständig.

1.3 Verwende eigene Objekte als Map-Schlüssel

Eine als String gespeicherte Produkt-ID hat bereits geeignete Gleichheitsregeln. Bei einem Schlüssel aus einer eigenen Klasse musst du entscheiden: Stellen zwei separate Objekte mit denselben Daten denselben Schlüssel dar?

Hashcodes grenzen die Suche ein; Gleichheit bestätigt sie

Eine HashMap nutzt hashCode(), um einen Schlüssel zu lokalisieren, und equals(), um eine Übereinstimmung zu prüfen. Gleiche Schlüssel müssen gleiche Hashcodes haben. Verschiedene Schlüssel können denselben Hashcode haben; der Gleichheitsvergleich unterscheidet sie trotzdem. Standardwertklassen wie String und Integer erfüllen diesen Vertrag bereits.

Ohne Überschreibungen erbt eine Klasse von Object eine Gleichheit auf Grundlage der Identität. Zwei getrennt erzeugte Punkte mit den Koordinaten 2 und 3 sind verschiedene Schlüssel, obwohl ihre Felder übereinstimmen:

labels.put(new Point(2, 3), "door");
String label = labels.get(new Point(2, 3));

Bei Referenzgleichheit ist label gleich null. Für den Zugriff wurde ein zweites Objekt erzeugt, nicht das zum Einfügen verwendete Objekt.

Überschreibe beide Methoden gemeinsam

Hier definieren die Koordinaten eines Punktes seinen Inhalt:

import java.util.Objects;

final class Point {
    private final int x;
    private final int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof Point)) {
            return false;
        }
        Point point = (Point) other;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

Die Identitätsprüfung behandelt dasselbe Objekt schnell. Die Typprüfung lehnt null und Objekte anderer Typen ab. Der letzte Vergleich prüft beide Koordinaten. Objects.hash(x, y) bildet den Hashcode aus denselben Feldern. Mit dieser Klasse liefert der Zugriff oben "door".

Überschreibst du nur equals, bleibt die geerbte Hashcode-Berechnung erhalten, die für separate Objekte mit gleichen Feldern keine gleichen Hashcodes garantiert. Eine Map kann dann einen gleichen Schlüssel übersehen. Ein konstanter Hashcode würde die Korrektheit erhalten, aber die Suche verlangsamen. Lässt du beide Überschreibungen im Editor erzeugen, hilft das, nicht zueinander passende Felder zu vermeiden.

Verwende die genaue Methodensignatur

public boolean equals(Point other) überlädt die Methode; sie ersetzt equals(Object) nicht. Der Map-Zugriff verwendet equals(Object), sodass die neue Überladung der Map keine inhaltliche Gleichheit vermittelt. Die Annotation @Override macht eine falsche Signatur zu einem Compilerfehler statt zu einem versteckten Zugriffsfehler.

Halte die Identität des Schlüssels stabil

Ändere keine Felder, die die Gleichheit oder den Hashcode eines Schlüssels bestimmen, während er gespeichert ist. Ändert sich ein gespeicherter Punkt von (2, 3) zu (5, 3), findet die Map ihn möglicherweise unter keinem der beiden Werte mehr, obwohl size() unverändert ist. Entferne ihn vor der Änderung und füge ihn danach wieder ein. Sind die Schlüsselfelder wie oben final, wird dieser Fehler verhindert.

Diese Regeln bestimmen auch die Zugehörigkeit zu einem HashSet. Eine ArrayList verwendet equals für Inhaltssuchen wie contains; für diese Suche braucht sie keine Hashcodes.

Wichtige Erkenntnisse

  • Gleiche Objekte müssen gleiche Hashcodes haben; ungleiche Objekte dürfen einen Hashcode teilen.
  • Überschreibe equals(Object) und hashCode() anhand passender Felder.
  • @Override erkennt eine versehentliche Überladung von equals.
  • Ändere die für Gleichheit und Hashcode relevanten Felder nicht, während ein Schlüssel gespeichert ist.
2

Zähle, gruppiere und indexiere Daten mit Maps

Eine Map kann beim Einlesen von Daten nützliche Informationen aufbauen: eine Anzahl für jedes Wort, eine Liste für jeden Kurs oder ein Objekt für jede ID. Entscheidend ist, was ein einzelner Wert darstellt. Eine Zahl sammelt ein Ergebnis; eine Liste oder Menge sammelt eine Gruppe; eine Objektreferenz ermöglicht einen Suchindex. Verfolge jede Aktualisierung ausgehend von einer leeren Map, damit das Verhalten bei ersten Vorkommen, wiederholten Schlüsseln und gemeinsam genutzten Objekten klar wird.

2.1 Zähle Vorkommen und berechne Summen je Schlüssel

Eine Häufigkeitstabelle hat für jedes unterschiedliche Element einen Schlüssel und eine Zahl, die angibt, wie oft es vorkommt. Das erste Vorkommen beginnt eine Zählung; jedes spätere Vorkommen aktualisiert denselben Eintrag.

Zähle ein Element nach dem anderen
HashMap<String, Integer> counts = new HashMap<>();
for (String word : text.split(" ")) {
    int oldCount = counts.getOrDefault(word, 0);
    counts.put(word, oldCount + 1);
}

Beim Text „the cat saw the dog and the cat ran“ fehlt das erste "the" noch. Seine alte Anzahl ist daher 0 und seine neue Anzahl 1. Die nächsten beiden Vorkommen ändern diesen Eintrag auf 2 und dann auf 3. "cat" endet bei 2; "saw", "dog", "and" und "ran" enden bei jeweils 1.

Es gibt 6 unterschiedliche Wörter, daher ist counts.size() gleich 6. Die Werte ergeben zusammen 9, die Anzahl der Wortvorkommen. Diese Angaben messen Unterschiedliches: Die Größe der Map ist nicht die Länge der ursprünglichen Folge.

Die Aktualisierung lässt sich in einer Zeile schreiben:

counts.put(word, counts.getOrDefault(word, 0) + 1);

Eine längere gleichwertige Form prüft containsKey, erhöht eine vorhandene Anzahl und speichert 1 für einen neuen Schlüssel. Alle gespeicherten Anzahlen sind bei diesem Muster nicht null.

Erhalte das bisherige Ergebnis

Der Aufruf von counts.put(word, 1) für jedes Wort überschreibt jede Anzahl wiederholt mit 1. Er hält fest, dass ein Wort existiert, verliert aber dessen Häufigkeit. counts.get(word) + 1 ohne Behandlung des ersten Vorkommens versucht, null per Unboxing umzuwandeln, und schlägt fehl. Der Standardwert gehört zum Lesen; die erhöhte Anzahl muss anschließend zurückgespeichert werden.

Entscheide, was als dasselbe Element zählt

Die Gleichheit von Strings ist exakt. "The" und "the" sind verschiedene Schlüssel, ebenso "cat" und "cat,". Behandelt die Aufgabe sie als dasselbe Wort, bereinige jedes Token vor dem Zählen. Wandle Text in Kleinbuchstaben um und entferne die Satzzeichen, die das Programm als Trennzeichen behandelt. Verwende eine einheitliche Regel, damit die Ergebnisse nicht davon abhängen, welche Schreibweise zuerst auftrat.

Der Schlüssel kann auch ein Zeichen sein. Mit HashMap<Character, Integer> erzeugt eine Schleife über "banana".toCharArray() die Werte a=3, n=2 und b=1 mit demselben Muster aus Lesen, Erhöhen und Speichern.

Summiere Beträge statt Vorkommen

Für Kategoriesummen addiere den aktuellen Betrag statt 1:

HashMap<String, Double> totals = new HashMap<>();
double oldTotal = totals.getOrDefault(category, 0.0);
totals.put(category, oldTotal + amount);

Lebensmittel 12,50, Transport 3,20 und Lebensmittel 7,25 ergeben Lebensmittel 19,75 und Transport 3,20. Der Standardwert ist 0.0, passend zum Werttyp Double. Die Map hat weiterhin einen Eintrag pro Kategorie, unabhängig davon, wie viele Beträge dazu beigetragen haben.

Lies die fertige Tabelle

Durchlaufe die Einträge, um die größte Anzahl oder Summe zu finden, und merke dir den besten Schlüssel und Wert. Lege bei Bedarf eine Regel für Gleichstände fest. Für eine alphabetische Ausgabe kopiert new TreeMap<>(counts) die Zuordnungen in sortierter Schlüsselreihenfolge. Die Anzahlwerte bleiben unverändert; das Sortieren der Schlüssel sortiert die Kategorien nicht nach ihren Summen.

Wichtige Erkenntnisse

  • Eine Häufigkeits-Map speichert eine Anzahl pro unterschiedlichem Schlüssel.
  • Lies die alte Anzahl mit null als Standardwert, addiere eins und speichere das Ergebnis.
  • Die Map-Größe zählt unterschiedliche Elemente; die Summe der Anzahlen misst die Vorkommen.
  • Normalisiere Text vor dem Zählen einheitlich.
  • Verwende dasselbe Aktualisierungsmuster, um Beträge pro Schlüssel zu addieren.
  • Wähle die Ausgabereihenfolge unabhängig von den angesammelten Werten.

2.2 Gruppiere Werte unter einem Schlüssel und verwende Listen und Mengen als Map-Werte

Ein Map-Wert kann eine Collection sein. Gehören mehrere Lernende zu einem Kurs, ist der Kurs ein Schlüssel und die zugehörige Liste enthält alle Teilnehmenden. Die Regel der Map für eindeutige Schlüssel gilt weiterhin: Die Liste ist der eine Wert für diesen Kurs.

Erstelle eine Gruppe, bevor du etwas hinzufügst
HashMap<Character, ArrayList<String>> groups = new HashMap<>();
for (String fruit : fruits) {
    char letter = fruit.charAt(0);
    if (!groups.containsKey(letter)) {
        groups.put(letter, new ArrayList<>());
    }
    groups.get(letter).add(fruit);
}

Für „apple“, „banana“, „avocado“, „cherry“ und „blueberry“ erzeugt die erste Frucht die Liste für a und fügt „apple“ hinzu. „banana“ erzeugt die Liste für b. „avocado“ findet die vorhandene Liste für a und hängt sich an. Das Ergebnis ist a → [apple, avocado], b → [banana, blueberry] und c → [cherry]. Jede Liste behält ihre eigene Einfügereihenfolge, obwohl die HashMap ihre Schlüssel nicht ordnet.

Die Prüfung lässt sich verkürzen:

groups.putIfAbsent(letter, new ArrayList<>());
groups.get(letter).add(fruit);

putIfAbsent behält eine vorhandene Liste bei, die nicht null ist. Das folgende get gibt diese Liste zurück, sodass etwas hinzugefügt werden kann.

Behalte die bereits aufgebaute Liste

Ein bedingungsloses groups.put(letter, new ArrayList<>()) innerhalb der Schleife ersetzt bei jedem Vorkommen die alte Liste. Nach dem nächsten add bleibt nur die letzte Frucht pro Buchstabe erhalten. Der umgekehrte Fehler ist, das Erzeugen ganz auszulassen: groups.get(letter).add(fruit) löst für einen neuen Schlüssel eine NullPointerException aus, weil noch keine Liste existiert.

Verstehe die Referenz

get gibt die gespeicherte Listenreferenz zurück. Das Hinzufügen ändert dieselbe Liste, sodass sie nicht erneut gespeichert werden muss. Das erklärt auch einen Fehler durch gemeinsames Nutzen:

ArrayList<String> shared = new ArrayList<>();
courses.put("Art", shared);
courses.put("Music", shared);
courses.get("Art").add("Jin");

Beide Schlüssel führen nun zu [Jin]. Zwei Schlüssel haben keine zwei Listen erzeugt. Erstelle für jede neue Gruppe eine eigene Liste, wenn die Gruppen unabhängig sein sollen.

Wähle Listen oder Mengen innerhalb von Gruppen

Eine Liste behält wiederholte Einfügungen. Eine Menge verhindert Duplikate innerhalb der jeweiligen Gruppe. Eine HashMap<String, HashSet<String>> kann daher die unterschiedlichen Kurszugehörigkeiten der Lernenden sammeln, ohne dieselbe Person in einem Kurs doppelt zu zählen. Die Mengenregel gilt innerhalb jedes Werts; die äußere Map hat weiterhin einen Eintrag pro Kurs.

Prüfe beim Lesen einer möglicherweise fehlenden Gruppe containsKey oder verwende groups.getOrDefault(letter, new ArrayList<>()). Ein fehlender Schlüssel liefert dann für diesen Aufruf eine leere Liste. Die Standardliste wird nicht automatisch eingefügt; ein Hinzufügen zu ihr erzeugt keine gespeicherte Gruppe.

Das Entfernen des letzten Elements einer Gruppe lässt den Schlüssel mit einer leeren Collection zurück. Soll das Programm leere Gruppen nicht mehr aufführen, prüfe isEmpty() und entferne auch diesen Schlüssel. Zähle Gruppen mit der Größe der äußeren Map und Elemente mit den Größen der inneren Collections.

Wichtige Erkenntnisse

  • Stelle sicher, dass eine Gruppe existiert, und füge dann etwas zu ihrer gespeicherten Liste oder Menge hinzu.
  • Erstelle für jede unabhängige Gruppe eine eigene Collection.
  • get gibt die gespeicherte Referenz zurück, sodass Änderungen an der inneren Collection kein zusätzliches put brauchen.
  • Listenwerte behalten Wiederholungen; Mengenwerte enthalten unterschiedliche Gruppenmitglieder.
  • Eine gespeicherte leere Gruppe hat weiterhin einen Map-Eintrag.

2.3 Rufe Objekte und Preise mit einem auf einer Map basierenden Suchindex schnell ab

Ein Suchindex ordnet einem identifizierenden Schlüssel ein Objekt zu. Eine Bibliothek kann ein Buch anhand der ISBN finden, ohne jedes Buch in einer Liste zu prüfen. Eine Nachschlagetabelle nutzt dieselbe Struktur, um einen Code mit einem einfachen Wert wie einem Produktpreis zu verbinden.

Wähle einen identifizierenden Schlüssel

Eine HashMap<String, Book> kann eine ISBN ihrem Buch zuordnen. Für jeden Zugriff wird nur der Schlüssel gebraucht. Der Name einer Person ist oft ein ungeeigneter eindeutiger Schlüssel: Wird eine weitere Person namens „Sam Lee“ unter demselben String gespeichert, ersetzt sie die vorherige Person. Verwende eine eindeutige ID oder eine gruppierende Map, wenn ein Name zu mehreren Personen führen soll.

Verwalte einen Suchindex innerhalb der Klasse, die für die Daten zuständig ist:

class Library {
    private HashMap<String, Book> byIsbn;

    Library() {
        byIsbn = new HashMap<>();
    }

    void addBook(Book book) {
        byIsbn.put(book.getIsbn(), book);
    }

    Book findByIsbn(String isbn) {
        return byIsbn.get(isbn);
    }
}

Hier stellt Book eine Methode getIsbn() bereit. Aufrufer verwenden addBook und findByIsbn; sie müssen nicht wissen, welche Map-Implementierung gespeichert ist. Das private Feld gibt der Klasse außerdem eine zentrale Stelle, um ihre Regeln für das Hinzufügen und Ersetzen von Büchern einzuhalten.

Prüfe ein fehlendes Ergebnis

Gibt findByIsbn den Wert null zurück, wurde kein Buch gefunden. Prüfe das Ergebnis, bevor du darauf eine Methode aufrufst:

Book found = library.findByIsbn("978-0-00-000000-2");
if (found != null) {
    found.setOnLoan(true);
}

Ein direkter Aufruf von setOnLoan auf einem fehlenden Ergebnis würde eine NullPointerException auslösen. Eine Methode wie hasBook(isbn) ist eine weitere Möglichkeit, Aufrufern die Prüfung auf einen Schlüssel zu erlauben.

Verfolge gemeinsam genutzte Objekte über Suchindizes hinweg

Eine Map speichert eine Objektreferenz, keine neue Kopie des Objekts. Ist dasselbe Buch in einer Liste aller Bücher, einer ISBN-Map und einer Gruppierung nach Autor enthalten, ändert setOnLoan(true) das eine Buch, auf das sich alle drei beziehen. So wird vermieden, dass drei separate Buchobjekte auseinanderlaufen.

Die Collection-Strukturen selbst müssen trotzdem gepflegt werden. Das Entfernen eines Buchs aus der ISBN-Map entfernt seine Referenz nicht aus der Liste eines Autors. Verwaltet eine Bibliothek beide Suchindizes, müssen ihre Methoden zum Hinzufügen und Entfernen beide aktualisieren. Werden diese Änderungen in Methoden wie addBook und removeBook gebündelt, hilft das, die Suchergebnisse konsistent zu halten.

Verwende eine Tabelle in einer Rechnung

Angenommen, eine Preistabelle enthält Kaffee 2,50, Tee 2,00 und Muffin 3,25. Für zwei Kaffees und einen Muffin:

double cost = 2 * prices.get("coffee") + prices.get("muffin");

Die Zwischensumme für den Kaffee beträgt 5,00; mit 3,25 dazu ergibt sich 8,25. Die Schlüssel identifizieren Produkte, und die Werte liefern die Beträge. Bei einem fehlenden Produkt muss vor der Rechnung ausdrücklich entschieden werden, was geschieht: Ein Standardwert von null würde es stillschweigend als kostenlos behandeln. Dieselbe Zugriffstechnik kann daher eine andere Regel für fehlende Schlüssel brauchen als eine Häufigkeitstabelle.

Wichtige Erkenntnisse

  • Ein Suchindex findet Objekte über einen identifizierenden Schlüssel.
  • Verwende einen eindeutigen Schlüssel oder gruppiere mehrere passende Objekte ausdrücklich.
  • Suchindizes teilen sich Objektreferenzen, aber beim Hinzufügen und Entfernen muss jeder Suchindex aktualisiert werden.
  • Halte Maps mit Daten privat und stelle Methoden bereit, die ihre Regeln einhalten.
3

Speichere Werte ohne Duplikate in Mengen

Manchmal geht es einfach darum, ob ein Wert schon einmal aufgetreten ist. Mengen passen direkt zu dieser Frage und können auch Wertegruppen vergleichen, etwa die Teilnehmenden zweier Veranstaltungen. Dass sie keine doppelten Elemente enthalten, beeinflusst sowohl deinen Code als auch die Bedeutung der endgültigen Größe. Arbeite zuerst mit der Mengenzugehörigkeit, verknüpfe dann Mengen und entscheide, ob ihre Werte in Einfügereihenfolge oder sortiert erscheinen sollen.

3.1 Speichere Werte ohne Duplikate und prüfe ihre Mengenzugehörigkeit mit HashSet

Eine Menge enthält jeden Wert höchstens einmal. Sie eignet sich für Fragen wie „Ist dieser Wert schon einmal aufgetreten?“ oder „Wie viele verschiedene Werte kommen vor?“. Ein HashSet erlaubt im Durchschnitt schnelle Prüfungen der Mengenzugehörigkeit, ohne eine Ausgabereihenfolge zu garantieren.

Füge Werte hinzu und prüfe sie
import java.util.HashSet;

HashSet<String> visited = new HashSet<>();
boolean first = visited.add("Oslo");
boolean second = visited.add("Lima");
boolean third = visited.add("Oslo");
visited.add("Pune");

Die drei gespeicherten booleschen Werte sind true, true und false. Das zweite „Oslo“ entspricht einem vorhandenen Element und wird daher nicht hinzugefügt. Die Größe der Menge ist 3. Das erneute Hinzufügen ersetzt keinen nummerierten Platz, weil eine Menge keinen Index hat.

visited.contains("Lima") liefert true. visited.remove("Lima") entfernt den Wert und liefert true; ein erneutes Entfernen liefert false. Verwende eine for-each-Schleife, um Werte zu durchlaufen. Es gibt kein get(0) für den ersten Wert eines HashSet.

Entferne Duplikate aus einer Liste
ArrayList<Integer> values = new ArrayList<>();
values.add(3);
values.add(1);
values.add(3);
values.add(2);
values.add(1);
HashSet<Integer> distinct = new HashSet<>(values);

Die Menge hat drei Werte: {1, 2, 3}. Ihre tatsächliche Iterationsreihenfolge ist nicht festgelegt. Die Ausgangsliste hat weiterhin fünf Elemente, weil der Konstruktor eine separate Collection erzeugt.

Verwende new LinkedHashSet<>(values), um die Reihenfolge der ersten Vorkommen beizubehalten; das ergibt 3, 1, 2. Verwende new TreeSet<>(values), um sortierte Werte zu erhalten: 1, 2, 3. Mengen stehen hier in geschweiften Klammern, um die Zugehörigkeit zu betonen; das Standard-toString() von Java verwendet für Mengen eckige Klammern.

Erkenne die erste Wiederholung

Das Ergebnis von add kann die Prüfung der Zugehörigkeit und das Einfügen verbinden:

HashSet<Integer> seen = new HashSet<>();
for (int number : numbers) {
    if (!seen.add(number)) {
        System.out.println(number);
        break;
    }
}

Für [4, 7, 2, 7, 4] gibt die Schleife 7 aus. Das ist der erste Wert, der zum zweiten Mal auftritt, obwohl 4 in der Folge früher erschien. Bevor sich 7 wiederholt, enthält die Menge 4, 7 und 2. Das fehlgeschlagene Einfügen löst den Abbruch aus.

Erkenne, was eine Menge nicht verraten kann

Eine Prüfung mit contains vor jedem add ist unnötig, weil add Duplikate bereits behandelt. Auch eine Liste mit einer contains-Prüfung kann Werte ohne Duplikate halten, aber jede Listensuche muss möglicherweise alle gespeicherten Elemente prüfen. Ein HashSet drückt die Regel direkt aus.

Bei eigenen Objekten ist die Gleichheit wichtig. Ein HashSet<Point> braucht ein inhaltsbasiertes equals und ein passendes hashCode, um getrennt erzeugte Punkte mit gleichen Koordinaten zusammenzufassen. Ohne diese Überschreibungen bleiben separate Instanzen separate Elemente.

Schließlich misst size() unterschiedliche Werte, keine Vorkommen. Die neun Wörter in „the cat saw the dog and the cat ran“ ergeben sechs unterschiedliche Wörter. Eine Menge verrät nicht mehr, dass „the“ dreimal vorkam; verwende eine Häufigkeits-Map, wenn diese Anzahlen wichtig sind.

Wichtige Erkenntnisse

  • HashSet speichert Werte ohne Duplikate, ohne Index und ohne garantierte Reihenfolge.
  • add gibt false zurück, wenn bereits ein gleicher Wert vorhanden ist.
  • Eine in eine Menge kopierte Liste verliert ihre Duplikate, ohne dass sich die Ausgangsliste ändert.
  • Verwende das Ergebnis von add, um einen wiederholten Wert zu erkennen.
  • Die Größe einer Menge zählt unterschiedliche Werte; für Häufigkeiten brauchst du eine Map.

3.2 Verknüpfe Mengen und verwalte ihre Reihenfolge

Mengen können Gruppen beschreiben und ihre Zugehörigkeit vergleichen. Steht dieselbe Person mehrfach auf zwei Veranstaltungslisten, reduziert eine Menge jede Liste zunächst auf die Personen, die teilgenommen haben. Mengenoperationen beantworten dann Fragen zu mindestens einer Veranstaltung, beiden Veranstaltungen oder nur einer.

Verknüpfe zwei Gruppen

Für Montag sei die Menge {Ana, Ben, Cai, Dee} und für Dienstag {Ben, Dee, Eva} gegeben.

FrageMethode auf einer Kopie von MontagErgebnis
Wer nahm an mindestens einem der Tage teil?addAll(tuesday){Ana, Ben, Cai, Dee, Eva}
Wer nahm an beiden Tagen teil?retainAll(tuesday){Ben, Dee}
Wer nahm nur am Montag teil?removeAll(tuesday){Ana, Cai}

Diese Operationen bilden Vereinigungsmenge, Schnittmenge und Differenzmenge. Sie ändern die aufrufende Menge und geben einen booleschen Wert zurück, der angibt, ob sie sich geändert hat. Sie geben keine neue Ergebnismenge zurück.

Erhalte das Original

Erstelle eine Kopie, bevor du die Zugehörigkeit änderst, wenn du die Montagsmenge noch brauchst:

HashSet<String> both = new HashSet<>(monday);
both.retainAll(tuesday);

both beginnt mit allen vier Namen vom Montag. retainAll entfernt Ana und Cai, weil sie am Dienstag fehlen. Die Montagsmenge selbst bleibt unverändert. Um nur die Personen vom Dienstag zu finden, beginne mit einer Kopie der Dienstagsmenge und entferne die Namen vom Montag. Das ergibt {Eva}. Die Differenz hat eine Richtung; kehrst du sie um, ändert sich die Frage.

Prüfe Teilmengen und Gleichheit

monday.containsAll(group) fragt, ob jeder Wert in group am Montag vorhanden ist. Für {Ben, Dee} liefert der Aufruf true: Diese Gruppe ist eine Teilmenge der Montagsmenge. Er verlangt nicht, dass die Montagsmenge nur diese beiden Personen enthält.

Zwei Mengen sind gleich, wenn ihre Elemente übereinstimmen, unabhängig von Einfügereihenfolge oder Implementierung. Ein HashSet mit „x“ und „y“ ist gleich einem TreeSet mit „y“ und „x“. Die Zugehörigkeit entscheidet über die Gleichheit von Mengen, daher kann die Reihenfolge allein sie nicht ungleich machen.

Wähle eine Reihenfolge für die Traversierung
ImplementierungReihenfolge beim Besuch der Elemente
HashSetKeine Garantie
LinkedHashSetEinfügereihenfolge
TreeSetSortierte Reihenfolge

Alle drei vermeiden Duplikate. Verwende LinkedHashSet, wenn es auf das erste Auftreten jedes Namens ankommt. Verwende TreeSet, wenn jeder Durchlauf bereits sortiert sein soll. Bei Strings folgt die natürliche Sortierung den Zeichencodes: Klein- und Großbuchstaben verhalten sich nicht wie ein gemeinsames Alphabet ohne Beachtung der Groß- und Kleinschreibung.

Ein TreeSet mit seinem parameterlosen Konstruktor braucht Elemente mit einem natürlichen Vergleich, etwa Strings, Zahlen oder Objekte, die Comparable implementieren. In dieser Menge kennzeichnet ein Vergleichsergebnis von null ein Duplikat. Eine Klasse ohne natürlichen Vergleich löst beim Einfügen eine ClassCastException aus. Ein expliziter Comparator ist eine weitere Möglichkeit, die Ordnung einer baumbasierten Collection festzulegen; die Beispiele mit dem parameterlosen Konstruktor verwenden die natürliche Ordnung.

Wichtige Erkenntnisse

  • addAll, retainAll und removeAll ändern die aufrufende Menge.
  • Kopiere eine Menge zuerst, wenn ihre ursprünglichen Elemente noch gebraucht werden.
  • containsAll prüft eine Teilmenge; die Gleichheit von Mengen ignoriert die Reihenfolge.
  • Wähle eine Hash-, Linked- oder Tree-Implementierung für eine nicht festgelegte Reihenfolge, Einfügereihenfolge oder sortierte Reihenfolge.
4

Programmiere mit den Interfaces List, Set und Map

Der Typ links in einer Collection-Deklaration teilt dem Rest des Programms mit, welche Operationen es verwenden kann. Die Klasse rechts stellt diese Operationen bereit und kann eine bestimmte Reihenfolge garantieren. Wenn du beide Seiten lesen kannst, lässt sich Collection-Code leichter ändern und Methoden lassen sich leichter wiederverwenden. Das hilft auch zu erklären, warum sich eine Liste, eine Menge und eine Map unterschiedlich verhalten, selbst wenn sie ähnlich aussehende Daten enthalten.

4.1 Deklariere Variablen und Parameter mit Interface-Typen

Ein Interface beschreibt Operationen, die eine implementierende Klasse bereitstellt. Es erlaubt einer Variablen zu beschreiben, was der Code braucht, während eine konkrete Klasse die Speicherung übernimmt. List, Set und Map sind Interfaces für Collections in java.util.

Lies beide Seiten einer Deklaration
List<String> names = new ArrayList<>();
Set<String> tags = new HashSet<>();
Map<String, Integer> counts = new HashMap<>();

Die linke Seite deklariert den Typ der Variablen. Die rechte Seite erzeugt ein Objekt einer Klasse, die das Interface implementiert. Importiere beide Typen, etwa java.util.List und java.util.ArrayList. Du kannst weder new List<>() noch new Map<>() schreiben: Ein Interface ist kein konkretes Objekt, das sich erzeugen lässt.

Code, der counts verwendet, kann put, get und entrySet aufrufen, weil Map sie deklariert. Sind alphabetisch sortierte Schlüssel nützlich, ändere die Erzeugung zu new TreeMap<>(). Vorhandene Aufrufe lassen sich weiterhin kompilieren. Ihre Reihenfolge kann sich ändern, weil Implementierungen unterschiedliche Reihenfolgen garantieren können; das Interface macht sie nicht in jedem Verhalten identisch.

Akzeptiere die Fähigkeiten, die eine Methode braucht

Eine Methode, die nur lange Wörter zählt, kann eine Collection annehmen:

static int countLong(Collection<String> words, int min) {
    int count = 0;
    for (String word : words) {
        if (word.length() >= min) {
            count++;
        }
    }
    return count;
}

Für [„a“, „tree“, „house“] und eine Mindestlänge von 4 gibt sie 2 zurück. Dieselbe Methode kann eine ArrayList, eine LinkedList, ein HashSet oder List.of(...) erhalten, weil sie die Elemente nur liest. Eine Menge kann Duplikate bereits entfernt haben und daher andere Eingabedaten liefern als eine Liste.

Ein Interface-Parameter vermeidet die Vorgabe einer bestimmten Speicherklasse, wenn die Methode sie nicht braucht. Sind Positionen nötig, verwende List als Parameter. Ist ein Zugriff über Schlüssel nötig, verwende Map.

Kenne die Grenzen des deklarierten Typs
List<String> names = new ArrayList<>();
names.ensureCapacity(100);  // does not compile

Das Objekt ist eine ArrayList, aber List deklariert ensureCapacity nicht. Der Compiler prüft den deklarierten Typ der Variablen. Verwende einen konkreten Klassentyp, wenn dessen spezielle Operation tatsächlich gebraucht wird; ändere gewöhnliche Listenparameter nicht nur, damit sie zur Klasse eines Aufrufers passen.

Ordne Map neben Collection ein

List und Set erweitern Collection, das Interface für eine Gruppe von Elementen. Es deklariert Methoden wie add, remove, contains, size, isEmpty, addAll und clear. Ob eine Zustandsänderung unterstützt wird, hängt von der tatsächlichen Collection ab.

Map erweitert Collection nicht. Eine Map speichert Zuordnungen und stellt Sichten bereit, die Collections sind: keySet() ist ein Set, values() eine Collection und entrySet() ein Set von Einträgen. Übergib counts.values() an eine Methode, die eine Collection von Werten braucht, nicht counts selbst.

Eine Klasse kann mehrere Interfaces implementieren. LinkedList implementiert sowohl List als auch Deque, ein Interface für doppelseitige Warteschlangen. Eine eigene Klasse nennt ihre zugesicherten Interfaces nach implements, wie in class Member implements Comparable<Member>.

Wichtige Erkenntnisse

  • Deklariere links das benötigte Interface und erzeuge rechts ein Objekt einer implementierenden Klasse.
  • Interface-Parameter nehmen verschiedene Implementierungen mit den benötigten Operationen an.
  • Über eine Variable sind nur die von ihrem Typ deklarierten Methoden zugänglich.
  • List und Set erweitern Collection; Map stellt Collection-Sichten bereit.

4.2 Verstehe die Garantien von List, Set und Map

Wähle ein Interface nach den Regeln, die deine Daten brauchen. Ähnlich aussehende Inhalte machen eine Liste, eine Menge und eine Map nicht austauschbar: Jede gibt Positionen, Wiederholungen und Gleichheit eine andere Bedeutung.

Vergleiche die Garantien
InterfaceWas es speichertWichtige Regel
ListElemente an Positionen ab 0Wiederholte Elemente sind erlaubt
SetUnterschiedliche ElementeKeine indexbasierte get-Operation
MapSchlüssel-Wert-PaareSchlüssel sind eindeutig; Werte dürfen sich wiederholen

ArrayList und LinkedList implementieren List. HashSet, LinkedHashSet und TreeSet implementieren Set. HashMap, LinkedHashMap und TreeMap implementieren Map. Hash-Varianten garantieren keine Traversierungsreihenfolge; Linked-Varianten behalten die Einfügereihenfolge bei; Tree-Varianten halten Elemente oder Schlüssel sortiert. Wird ein vorhandener Schlüssel in einer gewöhnlichen LinkedHashMap mit Einfügereihenfolge erneut eingefügt, behält er seinen Platz.

Achte auf das Entfernen aus Ganzzahllisten

Eine List<Integer> hat zwei relevante Überladungen:

List<Integer> numbers = new ArrayList<>(List.of(1, 5, 7));
numbers.remove(1);

Das Argument 1 ist ein int, daher entfernt Java den Index 1: den Wert 5. Das Ergebnis ist [1, 7]. Beginnst du erneut mit [1, 5, 7], wählt numbers.remove(Integer.valueOf(1)) das Entfernen nach Wert und lässt [5, 7] übrig. Das Wrapperobjekt macht die beabsichtigte Überladung eindeutig.

Vergleiche Inhalte nach der richtigen Regel

Zwei Listen sind gleich, wenn dieselben Elemente in derselben Reihenfolge vorkommen. Eine ArrayList [1, 2] ist gleich einer LinkedList [1, 2], aber nicht gleich einer Liste [2, 1]. Zwei Mengen vergleichen die Zugehörigkeit und ignorieren die Reihenfolge. Zwei Maps vergleichen Zuordnungen, sodass die Einfügereihenfolge ihre Gleichheit nicht beeinflusst. Ihre konkreten Klassen können verschieden sein, während ihre Inhalte nach der Regel des Interfaces gleich sind.

Erkenne nicht modifizierbare Collections
List<String> labels = List.of("a", "b");
Set<Integer> levels = Set.of(1, 2, 3);
Map<String, Double> prices = Map.of("tea", 2.0, "coffee", 2.5);

Diese Fabrikmethoden geben nicht modifizierbare Collections zurück. Versuche, ihre Inhalte hinzuzufügen, zu entfernen, zu ersetzen oder zu sortieren, lösen UnsupportedOperationException aus. Map.of akzeptiert bis zu zehn Schlüssel-Wert-Paare.

Alle drei lehnen null als Element, Schlüssel oder Wert mit NullPointerException ab. Set.of lehnt doppelte Elemente und Map.of doppelte Schlüssel mit IllegalArgumentException ab. List.of erlaubt Duplikate, weil eine Liste ein Element wiederholen darf. Die Iterationsreihenfolge der von den Fabrikmethoden erzeugten Mengen und Maps ist nicht festgelegt.

Kopiere, wenn Änderungen nötig sind

new ArrayList<>(labels) erzeugt eine modifizierbare Liste mit denselben Elementen. new HashSet<>(someList) und new HashMap<>(someMap) erzeugen ebenso separate Collection-Strukturen.

Diese Kopien sind flach: Sie enthalten dieselben Elementreferenzen. Das Entfernen eines Elements aus einer Kopie lässt die ursprüngliche Struktur unverändert, aber das Ändern eines veränderlichen Objekts über eine der beiden Collections ändert das gemeinsam genutzte Objekt. Eine nicht modifizierbare Collection verhindert Änderungen an ihrer Struktur; sie macht nicht jedes darin gespeicherte Objekt unveränderlich.

Wichtige Erkenntnisse

  • Listen haben Positionen und erlauben Duplikate; Mengen haben unterschiedliche Elemente; Maps haben eindeutige Schlüssel.
  • remove(1) entfernt bei einer Ganzzahlliste nach Index; remove(Integer.valueOf(1)) entfernt nach Wert.
  • Die Listengleichheit prüft die Reihenfolge; die Gleichheit von Mengen und Maps prüft den Inhalt unabhängig von der Einfügereihenfolge.
  • of-Fabrikmethoden erzeugen nicht modifizierbare Collections und lehnen null ab.
  • Set.of lehnt doppelte Elemente ab; Map.of lehnt doppelte Schlüssel ab.
  • Eine modifizierbare Kopie hat eine separate Collection-Struktur, teilt sich aber die Elementreferenzen.
5

Sortiere Collections mit Comparable

Beim Sortieren werden Werte in eine Ordnung gebracht, die anderer Code nutzen kann. Zahlen und Strings kennen ihre natürliche Ordnung bereits; Objekte eigener Klassen brauchen eine ausdrückliche Regel. Verfolge, wie eine Liste sortiert wird, und schreibe dann einen Vergleich, der Zahlen, Text und Gleichstände sicher behandelt. Die Regel ist über Listen hinaus wichtig: Eine sortierte Menge oder Map entscheidet damit auch, wann zwei Elemente oder Schlüssel denselben Platz einnehmen.

5.1 Sortiere Listen mit Zahlen und Strings

Eine Liste hat eine Reihenfolge, die aber lediglich widerspiegeln kann, wie Werte eingetroffen sind. Beim Sortieren wird die Liste nach einer Vergleichsregel neu angeordnet. Java stellt für Zahlen und Strings bereits eine natürliche Ordnung bereit.

Sortiere eine modifizierbare Liste direkt
List<Double> values = new ArrayList<>(List.of(3.5, -1.0, 2.25));
Collections.sort(values);

Importiere java.util.Collections. Dieselbe Liste enthält nun [-1,0; 2,25; 3,5]. Die Sortierung gibt void zurück, daher lässt sich values = Collections.sort(values) nicht kompilieren. Auch values.sort(null) sortiert in natürlicher Ordnung. Für ein Array verwende Arrays.sort(array); aus einem Array mit 5, 2 und 8 wird 2, 5, 8.

Sage die String-Reihenfolge Zeichen für Zeichen voraus

Der String-Vergleich betrachtet das erste unterschiedliche Zeichen. Ist ein String ein Präfix eines anderen, kommt der kürzere zuerst. Daher steht „apple“ vor „apples“.

Die Liste [„pear“, „Banana“, „apple“, „10“, „9“] wird zu [„10“, „9“, „Banana“, „apple“, „pear“] sortiert. Für diese Zeichen kommen Ziffern vor Großbuchstaben und Großbuchstaben vor Kleinbuchstaben. „10“ steht vor „9“, weil „1“ vor „9“ kommt; die String-Reihenfolge interpretiert Ziffernfolgen nicht als ganze Zahlen. Speichere numerische Daten als Zahlen, wenn eine numerische Ordnung nötig ist.

Verwende vorgefertigte alternative Ordnungen
names.sort(String.CASE_INSENSITIVE_ORDER);
values.sort(Collections.reverseOrder());

Der erste Aufruf ordnet [„pear“, „Banana“, „apple“] als [„apple“, „Banana“, „pear“], ohne die gespeicherte Groß- und Kleinschreibung zu ändern. Der zweite verwendet die absteigende natürliche Ordnung. Aus den Zahlen 4, 9 und 1 wird 9, 4 und 1. Diese Argumente sind Comparatoren, also Objekte, die eine alternative Ordnung bereitstellen.

Collections.reverse(list) kehrt nur die aktuelle Folge um. Das ergibt eine absteigende Reihenfolge, wenn die Folge bereits aufsteigend sortiert war; eine beliebige Liste wird dadurch nicht von selbst sortiert.

Erhalte die Reihenfolge bei Gleichständen

Das Sortieren von Listen ist stabil: Elemente, die beim Vergleich als gleich gelten, behalten ihre bisherige relative Reihenfolge. Ergibt ein Vergleich allein nach Punktzahl für zwei Personen einen Gleichstand, bleibt ihre bisherige Reihenfolge in der Liste erhalten. Stabilität bewahrt diese Eingabereihenfolge; sie erzeugt kein alphabetisches sekundäres Vergleichskriterium.

Erkenne Fehler und Abkürzungen

Eine Liste aus List.of(...) kann nicht direkt sortiert werden. Kopiere sie zuerst in eine ArrayList. Bei einer Klasse ohne Comparable schlägt die Typprüfung von Collections.sort(list) beim Kompilieren fehl. Der Aufruf von list.sort(null) auf solchen Objekten schlägt zur Laufzeit mit ClassCastException fehl, sobald ein Vergleich nötig ist.

Collections.max(collection) und Collections.min(collection) finden das größte beziehungsweise kleinste Element in natürlicher Ordnung, ohne die Collection umzuordnen. Bei einer leeren Collection lösen sie NoSuchElementException aus.

Für sortierte Map-Schlüssel kopiere entweder map.keySet() in eine ArrayList und sortiere die Kopie oder verwende eine TreeMap. Das Sortieren einer kopierten Schlüsselliste lässt die eigene Iterationsreihenfolge der Map unverändert.

Wichtige Erkenntnisse

  • Collections.sort ändert eine modifizierbare Liste direkt und gibt void zurück.
  • Die natürliche Ordnung von Strings vergleicht Zeichen, keine Zahlenwerte im Text.
  • Verwende vorgefertigte Comparatoren für umgekehrte Reihenfolge oder eine Ordnung ohne Beachtung der Groß- und Kleinschreibung.
  • Eine stabile Sortierung erhält die frühere relative Reihenfolge von Elementen mit gleichem Vergleichsergebnis.
  • Kopiere eine nicht modifizierbare Liste vor dem Sortieren.
  • min und max finden Extremwerte ohne Sortierung.

5.2 Implementiere Comparable in einer eigenen Klasse

Java kann nicht erraten, ob ein Mitglied nach Name, Körpergröße oder einem anderen Feld zuerst kommen soll. Implementiere Comparable, um der Klasse eine natürliche Ordnung zu geben. Sortierender Code kann dann jedes Objekt bitten, sich mit einem anderen Objekt dieser Klasse zu vergleichen.

Schreibe die Vergleichsmethode
class Member implements Comparable<Member> {
    private String name;
    private int height;

    Member(String name, int height) {
        this.name = name;
        this.height = height;
    }

    @Override
    public int compareTo(Member other) {
        return Integer.compare(this.height, other.height);
    }
}

Die Körpergröße wird in Zentimetern gemessen. Comparable<Member> legt fest, dass das andere Objekt ein Member ist; eine explizite Typumwandlung ist nicht nötig. public int compareTo(Member other) ist die erforderliche Methode. Das Standardinterface Comparable befindet sich in java.lang, daher ist dafür kein Import nötig.

Bei a.compareTo(b) setzt ein negatives Ergebnis a vor b, null setzt beide auf dieselbe Vergleichsposition, und ein positives Ergebnis setzt a nach b. Nur das Vorzeichen ist wichtig: -35 ist ein ebenso gültiges negatives Ergebnis wie -1.

Verfolge die Reihenfolge

Mit dem Vergleich der Körpergröße werden Ana 172, Ben 165 und Cai 180 zu Ben 165, Ana 172 und Cai 180 sortiert. Um größere Mitglieder zuerst zu setzen, vertausche die Argumente:

return Integer.compare(other.height, this.height);

Ändere die Regel bewusst. Das Vertauschen der Argumente kehrt die Richtung dieses Feldes um; es ändert weder die Bedeutung der Körpergröße noch die Daten eines Mitglieds.

Vergleiche ganze Zahlenwerte sicher

Eine Subtraktion erscheint bequem, kann aber bei einem Überlauf von int das falsche Vorzeichen zurückgeben. Für -2.000.000.000 und 2.000.000.000 ergibt das Subtrahieren des zweiten vom ersten Wert durch Überlauf 294.967.296, also ein positives Ergebnis. Integer.compare gibt korrekt ein negatives Ergebnis zurück.

Verwende für Dezimalfelder Double.compare(this.price, other.price). Die explizite Umwandlung einer Differenz in int verliert Informationen: (int) (1.8 - 1.5) ist 0, sodass ungleiche Preise beim Vergleich als gleich gelten. Eine Vergleichsmethode erhält die Ordnung, ohne die Differenz abzuschneiden.

Vergleiche Text und verwende die Regel erneut

Für die Namensordnung gib this.name.compareTo(other.name) zurück. Die Methode folgt der Zeichenordnung des Strings. compareToIgnoreCase bietet einen Textvergleich ohne Beachtung der Groß- und Kleinschreibung, wenn das die beabsichtigte Regel für das Feld ist.

Sobald eine Klasse eine natürliche Ordnung definiert, können Operationen wie Collections.sort, Collections.max sowie die Standardvergleiche von TreeSet oder TreeMap sie verwenden. Eine Klasse kann auch andere Interfaces implementieren, die nach implements durch Kommas getrennt werden.

Für die Klasse gibt es eine natürliche Ordnung; es wird nicht für jede Liste ein anderes compareTo ausgewählt. Verwende separate Comparator-Objekte, wenn ein Kontext die Namensordnung und ein anderer die Ordnung nach Körpergröße braucht. Ein Vergleich nur nach Körpergröße ergibt außerdem für alle gleichen Körpergrößen einen Gleichstand. Ob dieser Gleichstand akzeptabel ist, ist besonders bei sortierten Mengen wichtig.

Wichtige Erkenntnisse

  • Implementiere Comparable<YourClass> mit einer öffentlichen Methode compareTo.
  • Negative, null und positive Ergebnisse bedeuten davor, gleichgestellt und danach.
  • Verwende Integer.compare und Double.compare für eine sichere numerische Ordnung.
  • Vertausche Vergleichsargumente, um die Richtung eines Feldes umzukehren.
  • Eine Klasse hat eine natürliche Ordnung; Comparatoren stellen andere Ordnungen bereit.

5.3 Löse Gleichstände mit weiteren Vergleichskriterien auf und verwende sortierte Mengen und Maps

Ein primärer Vergleich lässt oft Gleichstände bestehen. Zwei Filme können dasselbe Jahr oder zwei Spielende dieselbe Punktzahl haben. Ein sekundäres Vergleichskriterium lässt das nächste Feld erst zum Zug kommen, wenn die vorherigen Felder beim Vergleich gleich sind.

Vergleiche Felder nach Priorität
@Override
public int compareTo(Film other) {
    int byYear = Integer.compare(this.year, other.year);
    if (byYear != 0) {
        return byYear;
    }
    return this.title.compareTo(other.title);
}

Das Jahr ist das wichtigste Kriterium. Der Titel ist nur bei gleichem Jahr wichtig. Up (2009), Avatar (2009) und Alien (1979) werden zu Alien (1979), Avatar (2009), Up (2009) sortiert. Würden die Titel zuerst verglichen, hätten sie Vorrang vor dem Jahr und die Sortierung würde eine andere Aufgabe erfüllen.

Die Richtungen können je Feld verschieden sein. Für Punkte absteigend und Namen von A bis Z beginne mit Integer.compare(other.points, this.points). Gib bei null this.name.compareTo(other.name) zurück. Würdest du die gesamte fertige Liste umkehren, würdest du auch die Namen innerhalb gleicher Punktzahlen umkehren.

Verstehe die Duplikatregel einer sortierten Menge

Ein TreeSet<Member> mit Standardeinstellungen verwendet den natürlichen Vergleich sowohl zum Ordnen der Elemente als auch zur Entscheidung, wann ein Element bereits vorhanden ist. Verwendet Member.compareTo nur die Körpergröße, ergibt der Vergleich von Ana 172 und Dee 172 null. Das Hinzufügen von Ana liefert true; das Hinzufügen von Dee liefert false. Ana bleibt das gespeicherte Element, auch wenn equals die beiden Mitglieder als verschieden betrachtet.

Eine Liste kann beide gleichgestellten Objekte behalten; eine baumbasierte Menge gibt ihnen eine Vergleichsposition. Ergänze das nötige sekundäre Vergleichskriterium, wenn sie in der Menge unterscheidbar sein müssen.

Stimme Vergleich und Gleichheit aufeinander ab

Eine Ordnung ist konsistent mit equals, wenn der Vergleich genau dann null zurückgibt, wenn equals true zurückgibt. Bei einer Klasse, deren Gleichheit auf Körpergröße und Name beruht, kann der Vergleich zuerst nach Körpergröße und dann nach Name diese Regel erfüllen. Beruht die Gleichheit auf einer anderen Identität, etwa einer Mitglieds-ID, stellt das Ergänzen des Namens als sekundäres Vergleichskriterium allein keine Konsistenz her.

Der Vergleich muss sich außerdem wie eine korrekte Ordnung verhalten. Steht a vor b, muss der umgekehrte Vergleich b nach a setzen. Steht a vor b und b vor c, muss a vor c stehen. Vergleichsmethoden für ganze Felder in einer festen Prioritätsreihenfolge unterstützen diese Regeln. Eine inkonsistente Methode kann Ergebnisse falsch ordnen oder beim Sortieren IllegalArgumentException auslösen.

Halte auch Map-Schlüssel sortiert

Eine TreeMap sortiert Schlüssel, keine Werte. Bei den Wortanzahlen von „the cat saw the dog and the cat ran“ ist der erste Schlüssel „and“ und der letzte „the“. firstKey() und lastKey() liefern diese äußersten Schlüssel. Deklariere eine TreeMap oder ein geeignetes Interface für sortierte Maps, wenn du Methoden aufrufst, die das einfache Map nicht deklariert.

Der Schlüsselvergleich definiert auch, welche Schlüssel übereinstimmen. Ein zweiter Schlüssel, dessen Vergleich null ergibt, aktualisiert die vorhandene Zuordnung, selbst wenn equals die Objekte unterscheidet. Baumbasierte Collections mit Standardeinstellungen brauchen natürlich vergleichbare Elemente oder Schlüssel; das Einfügen eines Objekts ohne passenden Vergleich löst ClassCastException aus. Ein ausdrücklich übergebener Comparator kann eine andere Ordnung festlegen.

Wichtige Erkenntnisse

  • Vergleiche zuerst das primäre Feld und berücksichtige spätere Felder nur bei einem Gleichstand.
  • Kehre nur die Felder um, die absteigend geordnet werden sollen.
  • Baumbasierte Collections behandeln ein Vergleichsergebnis von null als dasselbe Element beziehungsweise denselben Schlüssel.
  • Konsistenz mit equals verlangt genau dann ein Vergleichsergebnis von null, wenn Gleichheit vorliegt.
  • TreeMap sortiert Schlüssel; ihre Methoden für die Endpunkte liefern die äußersten Schlüssel.
  • Ein Vergleich muss Vorzeichen konsistent umkehren und die Ordnung über Dreiergruppen hinweg erhalten.
6

Wähle die passende Collection für eine Aufgabe

Die Wahl einer Collection beginnt mit den Fragen, die das Programm beantworten muss: nach Position, nach Zugehörigkeit oder über einen separaten Schlüssel. Reihenfolge und Duplikate grenzen die Auswahl weiter ein. Sobald die Daten zur Aufgabe passen, vergleiche, wie der Aufwand häufiger Operationen wächst, wenn weitere Werte hinzukommen. Eine kleine Änderung, etwa eine Menge einmal vor einer Schleife zu erstellen, kann wiederholte Suchen vermeiden, ohne das Programm schwerer lesbar zu machen.

6.1 Vergleiche den Aufwand gängiger Collection-Operationen

Der Aufwand einer Operation beschreibt, wie ihre Arbeit mit der Anzahl gespeicherter Elemente wächst. Er hilft, Code zu erkennen, der bei einem kleinen Beispiel schnell, bei einer großen Collection aber langsam ist.

Vergleiche das Wachstum, nicht die Sekunden

Konstante Laufzeit, O(1), bleibt ungefähr unabhängig von der Größe der Collection. Lineare Laufzeit, O(n), kann proportional zur Anzahl der Elemente wachsen. Logarithmische Laufzeit, O(log n), wächst bei zunehmender Größe langsam. Diese Bezeichnungen beschreiben das Wachstum, keine genauen Laufzeiten auf einem bestimmten Computer.

CollectionOperationAufwand
ArrayListget(i), set(i, x)Konstant
ArrayListAm Ende anhängenIm Durchschnitt konstant
ArrayListcontains, indexOf, Entfernen nach WertLinear
ArrayListNahe am Anfang einfügen oder entfernenLinear
HashMap / HashSetEinfacher Schlüsselzugriff oder Prüfung der Zugehörigkeit, Einfügen, EntfernenIm Durchschnitt konstant bei gut verteilten Hashcodes
TreeMap / TreeSetEinfacher Zugriff, Einfügen, EntfernenLogarithmisch
LinkedListAn einem der beiden Enden hinzufügen oder entfernenKonstant
LinkedListget(i) im AllgemeinenLinear

Eine Suche in einer ArrayList kann jedes Element prüfen; Änderungen am Anfang verschieben spätere Elemente. Eine LinkedList muss bis zu einer Position entlanggehen, sodass wiederholte indexbasierte Zugriffe aufwendig sein können. ArrayList ist eine nützliche Standardwahl für gewöhnliche Listenaufgaben.

Erkenne das wiederholte Durchsuchen

Angenommen, ein Programm prüft 10.000 Namen gegen eine Liste mit 100.000 Namen. Der Aufruf von list.contains(name) für jeden Namen kann bis zu 1.000.000.000 Gleichheitsprüfungen erfordern. Ein schnell aussehender Methodenaufruf ist bei dieser Verwendung trotzdem eine vollständige Suche.

Erstelle die Menge für die Zugehörigkeitsprüfung einmal:

Set<String> allowed = new HashSet<>(allowedNames);
int matches = 0;
for (String name : incomingNames) {
    if (allowed.contains(name)) {
        matches++;
    }
}

Der Aufbau der Menge mit 100.000 Elementen verursacht Aufwand, danach folgen 10.000 Zugehörigkeitsprüfungen mit durchschnittlich konstanter Laufzeit. Betrachtet man beide Schritte, wächst der Gesamtaufwand ungefähr mit der Summe der beiden Eingabegrößen statt mit ihrem Produkt. Würde die Menge innerhalb der Schleife jedes Mal neu erstellt, würde sich der Aufbauaufwand wiederholen und dieser Vorteil verloren gehen.

Verstehe Durchschnittsangaben richtig

Hashbasierte Operationen beruhen auf Schlüsseln, deren Hashcodes Werte gut verteilen. Ein konstanter Hashcode für jedes Objekt kann den Gleichheitsvertrag weiterhin erfüllen, macht den Zugriff aber langsam. Er erspart dir nicht ohne Nachteil das Schreiben einer brauchbaren Hashmethode.

Baumbasierte Collections halten eine sortierte Reihenfolge und führen grundlegende Operationen in logarithmischer Laufzeit aus. Eine Verdopplung der Elementanzahl erhöht den Suchaufwand nur geringfügig. Für 100.000 Elemente beträgt der Logarithmus zur Basis zwei etwa 16,6; das deutet die Größenordnung der Suche an und garantiert nicht genau 17 Vergleiche bei jedem Zugriff in einem Java-Baum.

Berücksichtige die gesamte Aufgabe

Der Aufbau einer zusätzlichen Menge kostet Zeit und Speicher. Bei einigen wenigen Elementen oder einem einzigen Zugriff kann die ursprüngliche Liste ausreichen. Für wiederholte Zugehörigkeitsprüfungen beseitigt eine wiederverwendbare Menge oft den Hauptaufwand. Beginne mit dem benötigten Verhalten und untersuche dann die am häufigsten wiederholten Operationen.

Wichtige Erkenntnisse

  • Wachstumsangaben beschreiben die Skalierung, keine gemessene Anzahl von Sekunden.
  • ArrayList bietet schnellen indexbasierten Zugriff, aber lineare Suchen und Änderungen am Anfang.
  • Hashbasierte Zugriffe sind bei geeigneten Hashcodes im Durchschnitt konstant; Baumzugriffe sind logarithmisch.
  • Erstelle eine Menge für Zugehörigkeitsprüfungen einmal, um wiederholte Listensuchen zu ersetzen.
  • Berücksichtige beim Vergleich vollständiger Lösungen Aufbauzeit und Speicher.

6.2 Wähle eine Collection, die zur Aufgabe passt

Die passende Collection hält die Informationen, die das Programm braucht, und macht seine wichtigsten Fragen leicht formulierbar. Entscheide über die Regeln der Daten, bevor du einen vertrauten Klassennamen wählst.

Frage, was ein Element identifiziert
Wichtigster BedarfAusgangswahlBeispiel
Einen Wert über einen separaten Schlüssel findenMapProduktcode zu Preis
Zugehörigkeit ohne Duplikate prüfenSetVergebene Benutzernamen
Positionen, Reihenfolge oder wiederholte Elemente behaltenListEine Wiedergabeliste mit wiederholten Liedern
Eine feste Anzahl von Plätzen verwaltenArrayZwölf monatliche Niederschlagsmessungen

Ein double[12] kann Niederschlag in Millimetern enthalten, wenn für jeden Platz der Monat bekannt ist. Eine Map, deren Schlüssel nur Positionen 0, 1, 2 und so weiter sind, fügt eine Ebene hinzu, die eine Liste oder ein Array bereits bereitstellt.

Wähle die benötigte Reihenfolge

Verwende für Maps und Mengen HashMap oder HashSet, wenn keine Reihenfolge nötig ist, LinkedHashMap oder LinkedHashSet für Einfügereihenfolge und TreeMap oder TreeSet für sortierte Schlüssel oder Elemente. Beginne für eine Liste für allgemeine Zwecke mit ArrayList.

Alphabetisch ausgegebene Wortanzahlen passen zu einer TreeMap<String, Integer>. Für unterschiedliche Schlagwörter in der Reihenfolge ihres ersten Auftretens passt ein LinkedHashSet<String>. Wiederholte Lieder brauchen eine Liste, selbst wenn die Lieder anderswo auch in einer Menge gespeichert sind: Das Verwerfen der Wiederholungen würde die Wiedergabeliste ändern.

Kombiniere Collections bei mehrschichtigen Daten

Lernende pro Kurs können als Map<String, List<String>> dargestellt werden; jeder Wert ist eine geordnete Liste von Einschreibungen. Schlagwörter pro Artikel können als Map<String, Set<String>> dargestellt werden; jeder Artikel erhält unterschiedliche Schlagwörter. Eine Rangliste kann eine List<Player> sein, die nach dem natürlichen Vergleich der Spielenden sortiert wird.

Die äußere und die innere Wahl beantworten unterschiedliche Fragen. Sollen Kurse alphabetisch aufgelistet und Lernende in Einschreibereihenfolge verwaltet werden, verwende außen eine TreeMap und innen eine Liste. Das Sortieren der Schlüssel sortiert nicht die Listen. Sollen doppelte Einschreibungseinträge ignoriert werden, verwende stattdessen eine Menge für die inneren Gruppen.

Halte zusammengehörige Daten zusammen

Zwei parallele Listen, eine für Namen und eine für Telefonnummern, beruhen auf übereinstimmenden Positionen. Das Entfernen eines Namens ohne seine Nummer bringt jede spätere Zuordnung durcheinander. Identifizieren Namen Personen eindeutig, kann eine Map die Zuordnung speichern. Wiederholen sich Namen oder gehören mehrere Felder zu einer Person, verwalte Personenobjekte in einer Liste oder indexiere sie über eine eindeutige ID.

Das wiederholte Durchsuchen einer Liste nach einem Feld ist ein weiterer Hinweis, eine Map als Suchindex zu erwägen. Behalte auch die Liste, wenn Ausgabereihenfolge und wiederholte Einträge wichtig sind, aber pflege beide Strukturen gemeinsam, wenn Daten hinzugefügt oder entfernt werden.

Prüfe die Elementregeln und den deklarierten Typ

Verwende eine Interface-Deklaration wie Map<String, Double> prices = new HashMap<>();, damit Aufrufer sich auf die benötigten Map-Operationen stützen. Hashbasierte Collections brauchen für eigene Schlüssel oder Elemente eine aussagekräftige Gleichheit und passende Hashcodes. Baumbasierte Collections mit Standardeinstellungen brauchen einen natürlichen Vergleich, der genau die Werte unterscheidet, die die Collection behalten soll. Diese Regeln tragen dazu bei, dass die gewählte Collection die vorgesehenen Daten darstellt.

Wichtige Erkenntnisse

  • Wähle Maps für den Schlüsselzugriff, Mengen für die Zugehörigkeit und Listen für Positionen oder Wiederholungen.
  • Arrays können eine feste Anzahl von Plätzen verwalten, auch für primitive Werte.
  • Wähle Einfügereihenfolge oder sortierte Reihenfolge bewusst.
  • Verschachtelte Collections erlauben unterschiedliche Regeln für äußere Schlüssel und innere Gruppen.
  • Halte zusammengehörige Felder zusammen und pflege mehrere Suchindizes über gemeinsame Methoden.
  • Stimme Gleichheits- und Vergleichsregeln auf die Werte ab, die die Collection behalten muss.

HashMaps und Collections in Java: Beispiele

6 Interaktive Lektionen

1

Verfolge eine Bestands-Map vom Speichern bis zum Abruf

13 Schritte
Verfolge Änderungen, prüfe Einträge sicher und mache eigene Schlüssel auffindbar.
  1. 1
    EinführungBeginne mit einer Produktfrage

    Ein Bestandsprogramm muss die Frage beantworten: „Wie viele Ordner sind verfügbar?“ Eine Map macht den Produktnamen zum Schlüssel und seine Anzahl zum Wert. Verfolge eine Map beim Ersetzen eines Werts, beim Zugriff auf einen fehlenden Schlüssel und beim Bereinigen. Untersuche dann, warum ein eigener Schlüssel fehlschlagen kann, obwohl seine Felder richtig aussehen. Jeder Zugriff hängt davon ab, was Java als denselben Schlüssel betrachtet.

  2. 2
    ErklärungErstelle eine Zuordnung pro Schlüssel

    Erstelle HashMap<String, Integer> stock = new HashMap<>();. String beschreibt die Schlüssel; Integer beschreibt die Werte. Die Map verwendet Referenztypen, daher kann int nicht das Werttypargument sein. Java wandelt ein Literal wie 6 in ein Wrapperobjekt um, wenn stock.put("folder", 6) es speichert. Der Diamant rechts lässt Java die beiden Typen ableiten.

  3. 3
    BeispielErsetze eine Anzahl

    Führe diese Aktualisierungen der Reihe nach aus:

    stock.put("folder", 6);
    stock.put("clip", 11);
    Integer old = stock.put("folder", 8);
    

    Der letzte Aufruf findet den vorhandenen Schlüssel folder, speichert 8 und gibt 6 in old zurück. Es gibt weiterhin zwei Schlüssel. Eine Map speichert den neuesten Wert für einen Schlüssel; sie addiert Mengen nicht automatisch und führt keine Historie darüber.

  4. 4
    HerausforderungLies, ohne einzufügen

    Welche Werte haben n und stock.size() nach diesem Lesezugriff? Die Map enthält weiterhin folder 8 und clip 11.

    int n = stock.getOrDefault("tape", 0);
    

    ---reveal---

    n ist 0, und die Größe bleibt 2. Der Standardwert ist ein Ergebnis für einen fehlenden Schlüssel, kein eingefügter Eintrag. Ein Lesezugriff mit get("tape") liefert stattdessen null, das nicht per Unboxing in einen int umgewandelt werden kann.

  5. 5
    ErklärungLies Paare zusammen

    Eine Schleife über Einträge liefert jeden Schlüssel und Wert zusammen:

    for (Map.Entry<String, Integer> e : stock.entrySet()) {
        System.out.println(e.getKey() + ": " + e.getValue());
    }
    

    Importiere java.util.Map. Die Schleife kann beide Zuordnungen ohne ein separates get anzeigen. Wird nur eine Summe benötigt, durchlaufe stock.values() und addiere die Mengen; wiederholte Mengen tragen weiterhin einzeln zur Summe bei.

  6. 6
    KernaussageGehe nicht von einem ersten Eintrag aus

    Die Ausgabe könnte folder vor clip oder clip vor folder aufführen. HashMap garantiert keine der beiden Reihenfolgen. Ein Ergebnis wie eine Summe bleibt davon unberührt, aber eine Regel wie „Behalte die erste Punktzahl bei einem Gleichstand“ kann von der Traversierung abhängen. Wähle LinkedHashMap für Einfügereihenfolge oder TreeMap für sortierte Schlüssel und lege bei gleichen Maximalwerten eine ausdrückliche Regel fest, wenn der Gewinner vorhersagbar sein muss.

  7. 7
    BeispielLösche während der Traversierung

    Angenommen, folder ist nun 0 und clip ist 11. Entferne Mengen mit dem Wert null über einen Iterator:

    Iterator<Map.Entry<String, Integer>> it =
        stock.entrySet().iterator();
    while (it.hasNext()) {
        if (it.next().getValue() == 0) {
            it.remove();
        }
    }
    

    Der Iterator entfernt seinen aktuellen Eintrag und läuft sicher weiter. Der Aufruf von stock.remove während einer for-each-Traversierung kann dagegen ConcurrentModificationException auslösen.

  8. 8
    HerausforderungErstelle eine separate Schlüsselkopie

    Vor dem Bereinigen wird keys mit new ArrayList<>(stock.keySet()) erstellt. Was geschieht mit der Bestands-Map, wenn keys.remove("folder") aufgerufen wird?

    ---reveal---

    Die Map behält ihre Zuordnung für folder. keys ist eine separate Liste der Schlüssel, die beim Kopieren vorhanden waren. Das Entfernen aus stock.keySet() selbst würde den Map-Eintrag entfernen, weil dieses Objekt eine verbundene Sicht ist.

  9. 9
    BeispielProbiere einen eigenen Schlüssel aus

    Angenommen, Bin hat die Felder row und column und keine Gleichheitsüberschreibungen. Speichere eine Bezeichnung mit new Bin(3, 4) und rufe sie dann mit einem anderen new Bin(3, 4) ab. Der Zugriff liefert null. Das sind zwei verschiedene Objekte, und das geerbte Object.equals verwendet Identität. Aus übereinstimmenden Feldwerten wurde noch keine Regel für übereinstimmende Schlüssel gemacht.

  10. 10
    ErklärungStimme Gleichheit und Hashcode-Berechnung aufeinander ab

    Für eine auf Koordinaten beruhende Behälteridentität überschreibe equals(Object other), sodass Zeile und Spalte verglichen werden, und überschreibe hashCode() anhand derselben Felder, etwa mit Objects.hash(row, column). Gleiche Koordinaten müssen gleiche Hashcodes ergeben. Ein übereinstimmender Hashcode allein begründet keine Gleichheit; die Gleichheitsprüfung unterscheidet weiterhin verschiedene Koordinatenschlüssel.

  11. 11
    HerausforderungErkenne eine Überladung

    Eine Klasse definiert public boolean equals(Bin other) und hashCode() anhand ihrer Koordinaten. Warum kann ein Zugriff mit einem separaten, gleich aussehenden Behälter trotzdem fehlschlagen?

    ---reveal---

    Der Parameter muss Object sein, um Javas Gleichheitsmethode zu überschreiben. Die Methode mit einem Bin-Parameter ist eine Überladung, sodass die geerbte Identitätsgleichheit bestehen bleibt. Ergänzt du @Override bei dieser falschen Signatur, deckt der Compiler den Fehler auf.

  12. 12
    HerausforderungKorrigiere einen Entwurf mit veränderlichem Schlüssel

    Ein Behälterschlüssel verwendet Zeile und Spalte in beiden Gleichheitsmethoden. Das Programm ändert seine Zeile, während er gespeichert ist, und kann seine Bezeichnung danach nicht finden. Wie sollte es den Ort aktualisieren und anschließend leere Bezeichnungen während der Traversierung sicher entfernen?

    ---reveal---

    Entferne die Zuordnung vor der Änderung des Schlüssels und füge sie danach wieder ein. Verwende zum Bereinigen während der Traversierung die eigene Entfernungsmethode des Eintragsiterators. Stabile Schlüsselidentität und sichere Traversierung lösen unterschiedliche Teile dieser Aktualisierung.

  13. 13
    ZusammenfassungNutze eine Prüfliste für Map-Aktualisierungen

    Entscheide bei einem fehlenden Suchergebnis, ob ein Standardwert oder eine ausdrückliche Prüfung auf Abwesenheit zur Aufgabe passt. Entscheide bei einer Schleife, ob die Reihenfolge wichtig ist und ob Schlüssel entfernt werden. Prüfe bei einem eigenen Schlüssel die genaue Signatur von equals(Object), passende Hashcode-Felder und eine stabile Identität. Diese Prüfungen finden unterschiedliche Ursachen desselben Symptoms: eine Zuordnung, die das Programm nicht wie erwartet verwenden kann.

2

Erstelle Teilnahmeinformationen beim Eintreffen von Datensätzen

12 Schritte
Zähle Datensätze, gruppiere unterschiedliche Teilnehmende und halte Suchindizes konsistent.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungGewinne aus eingehenden Datensätzen nützliche Antworten
  2. 2
    BeispielBeginne die Zählung einer Sitzung
  3. 3
    BeispielUnterscheide Sitzungen von Datensätzen
  4. 4
    HerausforderungKorrigiere eine zurückgesetzte Anzahl
  5. 5
    ErklärungErstelle eine Gruppe einmal
  6. 6
    BeispielVerfolge die innere Referenz
  7. 7
    HerausforderungFinde den Fehler durch gemeinsam genutzte Gruppen
  8. 8
    ErklärungIndexiere über einen identifizierenden Schlüssel
  9. 9
    KernaussageÄndere ein Objekt an mehreren Stellen
  10. 10
    HerausforderungHalte das Entfernen konsistent
  11. 11
    HerausforderungKombiniere Anzahlen mit eindeutiger Mitgliedschaft
  12. 12
    ZusammenfassungPrüfe ein erstes und ein wiederholtes Eintreffen
3

Vergleiche zwei Teilnahmegruppen

9 Schritte
Nutze Mengenzugehörigkeit, erhalte die Originale und gib die richtige Differenz aus.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungFrage nach den Personen, nicht nach der Anzahl der Besuche
  2. 2
    BeispielFasse wiederholte Erfassungen zusammen
  3. 3
    HerausforderungHalte beim ersten wiederholten Eintreffen an
  4. 4
    BeispielBehalte nur gemeinsame Mitglieder
  5. 5
    ErklärungWähle die Richtung der Differenz
  6. 6
    HerausforderungPrüfe eine ausgewählte Gruppe
  7. 7
    TippWähle eine nützliche Ausgabereihenfolge
  8. 8
    HerausforderungErstelle einen sortierten Bericht über fehlende Teilnehmende
  9. 9
    ZusammenfassungLies die aufrufende Menge als Ausgangsgruppe
4

Lies Collection-Deklarationen und Kopien

10 Schritte
Verwende Interfaces, erkenne Überladungen und unterscheide die Struktur von gemeinsam genutzten Objekten.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungLies beide Seiten der Deklaration
  2. 2
    ErklärungDeklariere, was der Aufrufer braucht
  3. 3
    BeispielVerwende zum Lesen einen allgemeineren Parameter
  4. 4
    HerausforderungUntersuche die fehlende Methode
  5. 5
    VerbindungWähle die Bedeutung der Inhalte
  6. 6
    BeispielVerfolge das Entfernen von Ganzzahlen
  7. 7
    HerausforderungKopiere vor dem Sortieren
  8. 8
    KernaussageUnterscheide Objektänderungen von Listenänderungen
  9. 9
    HerausforderungÜbergib die richtige Map-Sicht
  10. 10
    ZusammenfassungPrüfe Typ, Operation und Objekt
5

Erstelle eine Rangliste mit den richtigen Gleichständen

15 Schritte
Sortiere Strings und Objekte, schreibe sichere Vergleiche und prüfe die Zugehörigkeit zu sortierten Mengen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungWähle, was zuerst kommt
  2. 2
    BeispielSortiere dieselbe Liste
  3. 3
    ErklärungLies das erste unterschiedliche Zeichen
  4. 4
    HerausforderungVerwende eine bereitgestellte Ordnung
  5. 5
    ErklärungGib einer Klasse eine natürliche Ordnung
  6. 6
    BeispielVermeide einen falschen numerischen Gleichstand
  7. 7
    HerausforderungKehre das numerische Feld um
  8. 8
    BeispielLöse nur tatsächliche Gleichstände auf
  9. 9
    BeispielGehe die Rangliste durch
  10. 10
    HerausforderungSieh, was ein TreeSet behält
  11. 11
    KernaussageStimme Ordnung und Identität aufeinander ab
  12. 12
    VerbindungPrüfe den Schlüssel einer sortierten Map
  13. 13
    HerausforderungBehalte jedes Ergebnis in einer sortierten Rangliste
  14. 14
    TippSorge dafür, dass die Regel für Dreiergruppen funktioniert
  15. 15
    ZusammenfassungPrüfe einen Vergleich an zwei Stellen
6

Wähle Strukturen für eine Kursteilnehmerliste

10 Schritte
Stimme Zugriff, Zugehörigkeit, Reihenfolge und Aufwand aufeinander ab und vermeide wiederholte Suchen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungListe die Fragen des Programms auf
  2. 2
    BeispielErkenne die Suche innerhalb der Schleife
  3. 3
    ErklärungErstelle die Grundlage für Zugehörigkeitsprüfungen einmal
  4. 4
    HerausforderungVergleiche wachsende Eingaben
  5. 5
    BeispielBehalte wiederholte Einschreibungsdatensätze
  6. 6
    ErklärungWähle die äußere und innere Reihenfolge
  7. 7
    HerausforderungKorrigiere die falsche Duplikatregel
  8. 8
    TippBerücksichtige den Aufwand für die benötigte Ordnung
  9. 9
    HerausforderungKombiniere den fertigen Entwurf
  10. 10
    ZusammenfassungWähle das Verhalten vor der Geschwindigkeitsmessung

HashMaps und Collections in Java: Übungsaufgaben

50 Übungsfragen in 5 Sets

Set 1: Lies und aktualisiere Maps zuverlässig10 Übungsfragen

Frage 1 von 10

Eine leere HashMap<String, Integer> erhält put("brush", 5) und danach put("brush", 14). Wie groß ist sie und welchen Wert hat "brush"?
  1. Größe 2; Wert 14.
  2. Größe 1; Wert 14.
  3. Größe 1; Wert 19.
  4. Größe 2; Wert 5.
Antwort zeigenAntwort ausblenden
Antwort: B
Beide Aktualisierungen verwenden denselben Schlüssel, daher ersetzt die zweite den ersten Wert und die Map behält einen Eintrag. Der Wert ist 14, nicht 19: put addiert die eingehende Anzahl nicht zur vorherigen. Zum Aufsummieren brauchst du einen Ausdruck, der den Wert liest und aktualisiert.

Frage 2 von 10

Eine Map mit Mengenangaben, die nicht null sind, enthält den Schlüssel "tray" nicht. Was geschieht bei der Ausführung von int n = map.get("tray");?
  1. Sie speichert 0 in n und läuft weiter.
  2. Sie löst ClassCastException aus.
  3. Sie fügt "tray" mit dem Wert 0 ein.
  4. Sie löst NullPointerException aus.
Antwort zeigenAntwort ausblenden
Antwort: D
Ein get für einen fehlenden Schlüssel gibt null zurück. Bei der Zuweisung dieses Ergebnisses an einen int wird versucht, es per Unboxing umzuwandeln. Null hat keinen primitiven Ganzzahlwert, daher löst Java NullPointerException aus. Die Map liefert nicht allein deshalb null als Zahl und erzeugt keine Mengenangabe, weil die Zielvariable numerisch ist.

Frage 3 von 10

Eine Schleife muss jede Geräte-ID zusammen mit ihrem Status aus einer Map lesen. Welche Sicht liefert beides in einem Schleifenelement?
  1. entrySet()
  2. keySet()
  3. values()
  4. map.keySet().toArray()
Antwort zeigenAntwort ausblenden
Antwort: A
entrySet() liefert einen Eintrag, der sowohl einen Schlüssel als auch seinen zugeordneten Wert enthält. Eine Schleife über Schlüssel kann den Wert durch einen weiteren Zugriff abrufen, aber das Element der Schlüsselmenge selbst liefert nur den Schlüssel. Die Wertesicht kann nicht angeben, welcher Schlüssel zu welchem Status gehört.

Frage 4 von 10

Zwei separate Objekte sind nach einer korrekten equals-Methode gleich. Welche Hashcodes müssen sie haben?
  1. Unterschiedliche Ganzzahlwerte.
  2. Ihre jeweiligen Feldanzahlen.
  3. Denselben Ganzzahlwert.
  4. Ihre jeweiligen Speicheradressen.
Antwort zeigenAntwort ausblenden
Antwort: C
Gleiche Objekte müssen gleiche Hashcodes zurückgeben, damit eine hashbasierte Collection sie nach derselben Vergleichsregel finden kann. Unterschiedliche Hashcodes für gleiche Objekte verletzen diesen Vertrag. Die Umkehrung gilt nicht: Zwei ungleiche Objekte dürfen denselben Hashcode haben.

Frage 5 von 10

Eine Map enthält "beam" → 9. Das Programm führt Integer old = map.put("beam", 13); und danach Integer removed = map.remove("beam"); aus. Welche Werte haben old, removed und die endgültige Größe?
  1. 13, 13 und 0.
  2. 9, 9 und 0.
  3. 9, 13 und 1.
  4. 9, 13 und 0.
Antwort zeigenAntwort ausblenden
Antwort: D
Das Ersetzen gibt den vorherigen Wert 9 zurück, während der Eintrag nun 13 speichert. Das Entfernen gibt daher 13 zurück und löscht den einzigen Eintrag, sodass die Größe 0 bleibt. Wer das erste Ergebnis für 13 hält, verwechselt den von put zurückgegebenen mit dem gespeicherten Wert.

Frage 6 von 10

Eine Schleife zum Bereinigen eines Bestands durchläuft entrySet() und muss jeden Eintrag mit dem Wert null löschen. Wie soll sie den Eintrag während der Traversierung entfernen?
  1. Den Iterator der Traversierung verwenden und nach next() dessen remove() aufrufen.
  2. Eine for-each-Schleife verwenden und für jeden Schlüssel mit Wert null das remove() der Map aufrufen.
  3. Eine Schleife über Einträge verwenden und jeden Wert null durch eine Nullreferenz ersetzen.
  4. Eine Schleife über Werte verwenden und jeden Schlüssel mit Wert null direkt aus keySet() entfernen.
Antwort zeigenAntwort ausblenden
Antwort: A
Die eigene Entfernungsmethode des Iterators stimmt das Löschen mit seiner aktuellen Traversierungsposition ab. Direktes Entfernen über die Map oder eine verbundene Sicht ändert die Struktur hinter der Traversierung und kann ConcurrentModificationException auslösen. Das Ersetzen einer Mengenangabe durch eine Nullreferenz würde den Eintrag nicht löschen.

Frage 7 von 10

Eine Klasse Cell definiert equals(Cell other) und ein feldbasiertes hashCode. Separate Zellen mit gleichen Feldern stimmen als HashMap-Schlüssel nicht überein. Welche Methodenänderung behebt den Gleichheitsfehler?
  1. equals(Cell other) behalten und einen konstanten Hashcode zurückgeben.
  2. equals(Object other) mit denselben Feldvergleichen überschreiben.
  3. Die Gleichheitsmethode durch ein feldbasiertes toString() ersetzen.
  4. compareTo(Cell other) ergänzen, ohne eine Gleichheitsmethode zu ändern.
Antwort zeigenAntwort ausblenden
Antwort: B
Eine Map verwendet equals(Object). Die Methode mit Cell-Parameter ist daher eine Überladung und lässt die geerbte Identitätsgleichheit bestehen. Überschreibe die Methode mit Object-Parameter und verwende passende Felder für die Hashcode-Berechnung. Eine Änderung des Hashcodes allein kann nicht dafür sorgen, dass die falsche Gleichheitsmethode beim Zugriff verwendet wird.

Frage 8 von 10

Eine Suche in einer HashMap merkt sich einen Schlüssel nur, wenn seine Punktzahl echt größer als die bisher beste Punktzahl ist. Zwei Schlüssel haben dieselbe höchste Punktzahl. Welches Ergebnis kann das Programm garantieren?
  1. Einen der gleichstehenden Schlüssel, ohne garantierte Reihenfolge bei Gleichstand.
  2. Den gleichstehenden Schlüssel, der zuerst in die Map eingefügt wurde.
  3. Den gleichstehenden Schlüssel mit dem alphabetisch ersten Namen.
  4. Den gleichstehenden Schlüssel, der zuletzt in die Map eingefügt wurde.
Antwort zeigenAntwort ausblenden
Antwort: A
Die Suche behält den zuerst besuchten Schlüssel mit der höchsten Punktzahl, weil eine gleiche Punktzahl die Prüfung auf echt größer nicht erfüllt. Eine HashMap garantiert weder Einfüge- noch alphabetische Traversierungsreihenfolge. Ein vorhersagbares Ergebnis bei Gleichstand braucht eine ausdrückliche Regel oder eine dafür gewählte Reihenfolge.

Frage 9 von 10

Eine Map enthält anfangs "ink" → 4 und "paper" → 0. keys ist eine neue ArrayList, die aus ihrer Schlüsselmenge kopiert wurde. Das Programm entfernt "ink" aus keys, entfernt "paper" über die Schlüsselmengensicht der Map und verdoppelt dann alle verbleibenden Map-Werte. Was bleibt in der Map?
  1. Nur "paper" → 0.
  2. Keine Zuordnungen bleiben.
  3. Nur "ink" → 8.
  4. Sowohl "ink" → 8 als auch "paper" → 0.
Antwort zeigenAntwort ausblenden
Antwort: C
Die kopierte Liste ist unabhängig, daher bleibt die Zuordnung für ink erhalten, wenn es dort entfernt wird. Die Schlüsselmengensicht ist verbunden, daher löscht das Entfernen von paper dort die zugehörige Zuordnung. Das Verdoppeln des verbleibenden Werts für ink ergibt 8; würde man die kopierte Liste als weitere verbundene Sicht behandeln, würde man fälschlich beide Einträge entfernen.

Frage 10 von 10

Gleichheit und Hashcode-Berechnung von Location verwenden eine veränderliche Koordinate. Ein Schlüssel wird gespeichert und seine Koordinate anschließend geändert, während er gespeichert ist; seine Zuordnung wird beim Zugriff nun übersehen. Welche Aktualisierungsfolge sollte der Entwurf verwenden, um diesen Fehler zu verhindern?
  1. Koordinate ändern; über die neue Koordinate abrufen; erneut einfügen.
  2. Vor der Änderung entfernen; Koordinate ändern; erneut einfügen.
  3. Koordinate ändern; equals ersetzen; über die alte Koordinate abrufen.
  4. Zweite Referenz behalten; Koordinate ändern; mit ihr abrufen.
Antwort zeigenAntwort ausblenden
Antwort: B
Das Entfernen muss erfolgen, solange der Schlüssel noch die beim Einfügen verwendete Identität für Gleichheit und Hashcode hat. Danach kann das Programm ihn ändern und unter der neuen Identität wieder einfügen. Ein Zugriff mit derselben Referenz nach der Änderung behebt das Problem nicht: Der geänderte Hashcode kann weiterhin am gespeicherten Eintrag vorbeiführen.
Set 2: Erstelle Häufigkeiten und vergleiche Gruppen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Eine Häufigkeits-Map erfasst "north" → 4, "south" → 2 und "west" → 3. Wie viele unterschiedliche Schlüssel enthält sie?
  1. 9
  2. 4
  3. 3
  4. 2
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Ein HashSet enthält bereits "cedar". Was gibt ein weiterer Aufruf von add("cedar") zurück?
  1. false
  2. true
  3. null
  4. Den gespeicherten String.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Ein Kurs muss jede teilnehmende Person nur einmal aufführen, auch wenn doppelte Anmeldedatensätze eintreffen. Welche Regel für die innere Collection passt zu jeder Kursgruppe?
  1. Eine Liste von Teilnehmer-IDs.
  2. Eine ganzzahlige Datensatzanzahl.
  3. Eine Teilnehmer-ID als String.
  4. Eine Menge von Teilnehmer-IDs.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Die Schleife verarbeitet "red", "gold", "red", "blue", "gold", "red" mit counts.put(word, counts.getOrDefault(word, 0) + 1). Wie groß sind die Anzahl für red und die Map-Größe?
  1. Anzahl red 1; Größe 3.
  2. Anzahl red 3; Größe 3.
  3. Anzahl red 3; Größe 6.
  4. Anzahl red 6; Größe 3.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Innerhalb einer Gruppierungsschleife wird für jeden eingehenden Datensatz groups.put(team, new ArrayList<>()); gefolgt von groups.get(team).add(name); ausgeführt. Ein Team erhält Omar, Pia und dann Ren. Was bleibt unter diesem Team?
  1. [Omar, Pia, Ren]
  2. [Ren]
  3. [Omar]
  4. Eine leere Liste.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

A = {2, 5, 8, 11} und B = {5, 11, 14}. Eine kopierte Menge C beginnt mit A und führt dann C.removeAll(B) aus. Was enthält C?
  1. {5, 11}
  2. {14}
  3. {2, 5, 8, 11, 14}
  4. {2, 8}
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Dasselbe Device-Objekt wird in einer Liste und einer ID-Map gespeichert. Es wird aus der Map abgerufen, danach ändert sich sein Statusfeld. Welchen Status zeigt die in der Liste gespeicherte Referenz?
  1. Den geänderten Status desselben Objekts.
  2. Den ursprünglichen Status eines separat kopierten Objekts.
  3. Eine Nullreferenz, bis der Listeneintrag ersetzt wird.
  4. Den geänderten Status erst nach einem zweiten put in der Map.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Die Folge lautet [12, 7, 4, 12, 7]. Eine Schleife hält beim ersten !seen.add(n) an. Welche Zahl wird ausgegeben?
  1. 7
  2. 4
  3. 12
  4. Keine Zahl.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Eine ArrayList wird sowohl unter "Morning" als auch unter "Evening" gespeichert. Das Programm fügt über Morning "Lee" hinzu, ersetzt dann die Zuordnung von Evening durch eine neue Liste und fügt über Evening "Jo" hinzu. Wie lauten die endgültigen Gruppen?
  1. Morning [Lee]; Evening [Jo].
  2. Morning [Lee, Jo]; Evening [Lee, Jo].
  3. Morning []; Evening [Lee, Jo].
  4. Morning [Jo]; Evening [Jo].
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

A = {1, 3, 6} und B = {3, 6, 9}. C wird aus A kopiert und führt retainAll(B) aus. D wird aus B kopiert und führt removeAll(C) aus. Was ist D und was ist das Ergebnis von A.containsAll(C)?
  1. D = {1}; das Ergebnis ist true.
  2. D = {9}; das Ergebnis ist false.
  3. D = {3, 6, 9}; das Ergebnis ist false.
  4. D = {9}; das Ergebnis ist true.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 3: Verwende Interfaces und sortiere Daten10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Was ist in Set<String> codes = new HashSet<>(); der deklarierte Typ von codes?
  1. HashSet<String>
  2. String
  3. Collection<HashSet>
  4. Set<String>
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Was bedeutet ein positiver Wert, den a.compareTo(b) zurückgibt?
  1. a steht in dieser Ordnung vor b.
  2. a und b stehen in dieser Ordnung gleich.
  3. a steht in dieser Ordnung nach b.
  4. a hat ein größeres numerisches Feld.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Eine veränderliche List<Integer> beginnt als [4, 8, 12]. Sie führt remove(1) aus. Was bleibt übrig?
  1. [4, 12]
  2. [8, 12]
  3. [4, 8]
  4. [4, 8, 12]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Wie lautet die natürlich sortierte Reihenfolge der Strings "zebra", "Apron", "18", "3", "ant"?
  1. [„3“, „18“, „ant“, „Apron“, „zebra“]
  2. [„18“, „3“, „Apron“, „ant“, „zebra“]
  3. [„18“, „3“, „ant“, „Apron“, „zebra“]
  4. [„Apron“, „ant“, „zebra“, „18“, „3“]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Eine Methode, die nur liest, nimmt Collection<String> an. Ein Aufrufer hat Map<String, String> labels und möchte, dass die Methode jeden Bezeichnungswert verarbeitet. Was sollte übergeben werden?
  1. labels.values()
  2. labels
  3. labels.entrySet()
  4. labels.keySet().iterator()
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Preisvergleich gibt (int) (this.price - other.price) zurück. Was geht bei den Preisen 6,8 und 6,3 schief?
  1. Er setzt 6,8 immer vor 6,3.
  2. Er überschreitet den int-Wertebereich.
  3. Er gibt für ungleiche Preise null zurück.
  4. Er ändert beide gespeicherten Preise in Ganzzahlen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Ergebnisse müssen nach Punkten absteigend und dann nach Namen von A bis Z sortiert werden. Der primäre Vergleich ist ungleich null. Was sollte compareTo als Nächstes tun?
  1. Die Namen vergleichen und das Ergebnis zurückgeben.
  2. Null zurückgeben, um die Eingabereihenfolge zu behalten.
  3. Einen negierten Namensvergleich zurückgeben.
  4. Diesen primären Vergleich zurückgeben.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Eine modifizierbare Liste enthält ein veränderliches Ticket-Objekt. Eine zweite ArrayList wird daraus kopiert. Das Programm ändert über die Kopie die Bezeichnung des Tickets und leert dann die Kopie. Was enthält die ursprüngliche Liste?
  1. Eine leere Liste ohne Ticket.
  2. Dasselbe Ticket mit geänderter Bezeichnung.
  3. Ein separates Ticket mit ursprünglicher Bezeichnung.
  4. Dasselbe Ticket mit ursprünglicher Bezeichnung.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Eine Klasse vergleicht nach Stufe absteigend und dann nach Code aufsteigend. Die Datensätze lauten Delta 2, Beta 4, Alpha 2 und Echo 4. Welche Reihenfolge ergibt sich?
  1. Echo 4, Beta 4, Delta 2, Alpha 2.
  2. Alpha 2, Beta 4, Delta 2, Echo 4.
  3. Beta 4, Echo 4, Alpha 2, Delta 2.
  4. Alpha 2, Delta 2, Beta 4, Echo 4.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Reading.equals verwendet Stations-ID und Temperatur, der natürliche Vergleich aber nur die Temperatur. Ein TreeSet mit Standardeinstellungen erhält A bei 16, B bei 16 und dann C bei 12. Wie groß ist es und welche IDs bleiben erhalten?
  1. Größe 2; IDs C und A.
  2. Größe 3; IDs C, A und B.
  3. Größe 2; IDs C und B.
  4. Größe 1; nur ID C.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 4: Untersuche das Verhalten von Collections10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Ein Programm speichert den Niederschlag in Millimetern auf je einem Platz für jeden der zwölf Monate. Es braucht eine feste Anzahl primitiver numerischer Plätze. Welche Struktur passt direkt?
  1. Ein Set<Double> mit Messwerten.
  2. Ein double[12]-Array.
  3. Eine Map<Double, String> mit Monaten.
  4. Ein HashSet<Integer> mit Monatsnummern.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Eine HashMap enthält den Schlüssel "pending", dem ausdrücklich null zugeordnet ist. Was gibt getOrDefault("pending", 20) zurück?
  1. 20
  2. 0
  3. null
  4. Eine Ausnahme beim Zugriff selbst.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Was geschieht bei der Auswertung von Set.of("draft", "final", "draft")?
  1. Der Aufruf löst IllegalArgumentException aus.
  2. Der Aufruf gibt eine Menge mit zwei Elementen zurück.
  3. Der Aufruf gibt eine Liste mit drei Elementen zurück.
  4. Der Aufruf löst UnsupportedOperationException aus.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Ein Mitgliederindex verwendet Anzeigenamen als Schlüssel. Zwei verschiedene Mitglieder namens "Ari Chen" werden eingefügt, und das erste lässt sich unter diesem Namen nicht mehr abrufen. Welcher Entwurf erhält beide direkt für den einzelnen Zugriff?
  1. Den Namensschlüssel behalten, aber TreeMap verwenden.
  2. Den Namensschlüssel in einer LinkedHashMap behalten.
  3. Put erneut mit demselben Namen aufrufen.
  4. Nach der eindeutigen ID jedes Mitglieds indexieren.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Eine veränderliche Liste enthält derzeit [10, 2, 7]. Was enthält sie nach Collections.reverse(list)?
  1. [10, 7, 2]
  2. [2, 7, 10]
  3. [7, 10, 2]
  4. [7, 2, 10]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Programm prüft wiederholt, ob IDs in einer großen ArrayList vorkommen, und braucht für diese Prüfungen keine Positionen. Welche Änderung vermeidet das wiederholte vollständige Durchsuchen?
  1. Innerhalb der Abfrageschleife ein neues HashSet erstellen.
  2. Die ArrayList einmal in eine LinkedList kopieren.
  3. Vor der Abfrageschleife ein HashSet erstellen.
  4. Für jede Abfrage eine neue ArrayList sortieren.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine gruppierende Map hat keinen Schlüssel "Support". Das Programm wertet List<String> result = groups.getOrDefault("Support", new ArrayList<>()); aus und fügt dann "Nia" zu result hinzu. Was gibt ein späteres groups.get("Support") zurück?
  1. null, weil der Standardwert nie eingefügt wurde.
  2. Eine Liste mit Nia, weil der Standardwert zur Gruppe wurde.
  3. Eine leere Liste, weil der Standardwert vor dem Hinzufügen gespeichert wurde.
  4. Eine Ausnahme, weil eine ungespeicherte Standardliste nicht geändert werden kann.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Die Gleichheit von ScoreKey verwendet Team und Punkte; der natürliche Vergleich verwendet nur Punkte. Eine TreeMap mit Standardeinstellungen erhält den Schlüssel East-30 mit dem Wert "old", West-30 mit dem Wert "new" und dann North-18 mit dem Wert "low". Wie groß ist sie und welcher Wert wird mit East-30 gefunden?
  1. Größe 3; der Wert ist "old".
  2. Größe 2; der Wert ist "new".
  3. Größe 2; der Wert ist "old".
  4. Größe 1; der Wert ist "low".
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

A = {4, 7, 10} und B = {7, 10, 13}. Eine Kopie U von A führt zuerst addAll(B) und dann removeAll(A) aus. Was ist U und wurde eines der Originale geändert?
  1. U = {4}; beide Originale sind unverändert.
  2. U = {4, 13}; nur A wurde geändert.
  3. U = {7, 10}; nur B wurde geändert.
  4. U = {13}; beide Originale sind unverändert.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein Bericht braucht Kurse alphabetisch und die unterschiedlichen Mitglieder-IDs jedes Kurses in der Reihenfolge ihrer ersten Anmeldung. Welche äußere und innere Implementierung passen zusammen?
  1. TreeMap außen; LinkedHashSet innen.
  2. LinkedHashMap außen; TreeSet innen.
  3. TreeMap außen; ArrayList innen.
  4. HashMap außen; LinkedHashSet innen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 5: Kombiniere Zugriff, Gruppierung und Ordnung10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Was bestimmt die Gleichheit einer ArrayList und einer LinkedList, die dieselben Elementwerte enthalten?
  1. Die Werte müssen in derselben Reihenfolge erscheinen.
  2. Die Listen müssen dieselbe konkrete Klasse haben.
  3. Nur die Anzahl unterschiedlicher Werte muss übereinstimmen.
  4. Die Elementreferenzen müssen alle identisch sein.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Eine zunächst leere Summen-Map verarbeitet Reparaturen 4,25, Lieferung 2,50 und Reparaturen 3,75 durch Addition mit null als Standardwert. Wie groß ist sie und wie hoch ist die Reparatursumme?
  1. Größe 3; Reparatursumme 8,00.
  2. Größe 2; Reparatursumme 3,75.
  3. Größe 2; Reparatursumme 10,50.
  4. Größe 2; Reparatursumme 8,00.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Eine eigene Klasse mit korrekter Gleichheitsmethode gibt für jede Instanz denselben Hashcode zurück. Was geschieht mit der Korrektheit und Zugriffsgeschwindigkeit eines HashSet?
  1. Alle Werte werden zu einem Element zusammengefasst, wodurch der Zugriff schneller wird.
  2. Unterschiedliche ungleiche Werte bleiben erhalten, aber Zugriffe können langsamer werden.
  3. Unterschiedliche Werte bleiben erhalten und konstanter Zugriffsaufwand ist garantiert.
  4. Jedes Einfügen scheitert beim Kompilieren, weil sich Hashcodes wiederholen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Eine Temperaturklasse muss zwei double-Felder aufsteigend vergleichen, ohne durch eine explizite Typumwandlung falsche Gleichstände zu erzeugen. Welcher Rückgabeausdruck passt?
  1. (int) (this.value - other.value)
  2. Double.compare(other.value, this.value)
  3. Double.compare(this.value, other.value)
  4. Integer.compare((int) this.value, (int) other.value)
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Eine Map enthält zwei verschiedene Schlüssel, denen jeweils 6 zugeordnet ist. Welche Summe ergibt das Addieren von map.values()?
  1. 12
  2. 6
  3. 2
  4. 1
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Katalog verwaltet dieselben Item-Objekte in einem ID-Suchindex und einem Suchindex von Kategorien zu Listen. Die Kategorie eines Artikels ändert sich von Cables zu Adapters. Das Ändern seines Kategoriefeldes allein lässt ihn in der Liste Cables. Welche Aktualisierung hält die Suchindizes konsistent?
  1. In der ID-Map ersetzen; beide Kategorielisten unverändert lassen.
  2. Die ID-Map zur TreeMap ändern; beide Kategorielisten unverändert lassen.
  3. Die Referenz zwischen den Kategorielisten verschieben; die ID-Zuordnung behalten.
  4. Den Artikel unter der alten Kategorie kopieren; seine ID-Zuordnung löschen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine Spielerklasse definiert Gleichheit nach Name und Punktzahl und vergleicht nach Punktzahl absteigend und dann Name aufsteigend. Ein TreeSet mit Standardeinstellungen erhält Mira 9, Axel 12, Mira 9 und Bo 9 als separate Objekte. Welche geordneten Elemente ergeben sich?
  1. Axel 12, Mira 9, Bo 9.
  2. Axel 12, Mira 9, Mira 9, Bo 9.
  3. Bo 9, Mira 9, Axel 12.
  4. Axel 12, Bo 9, Mira 9.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Programm hat eine Liste zugelassener Werte und eine Abfrageliste. Beide Größen verdoppeln sich. Vergleiche wiederholte vollständige Listensuchen mit dem einmaligen Aufbau eines HashSet zugelassener Werte und anschließenden Abfragen bei geeigneter Hashcode-Berechnung. Wie wächst ihr Gesamtaufwand?
  1. Beide Gesamtaufwände können sich vervierfachen, weil beide Eingaben doppelt so viele Werte enthalten.
  2. Der Listensuchaufwand kann sich vervierfachen; Mengenaufbau und Abfragen verdoppeln sich ungefähr.
  3. Der Listensuchaufwand verdoppelt sich ungefähr; Mengenaufbau und Abfragen bleiben konstant.
  4. Beide Gesamtaufwände bleiben konstant, weil jeder einen Methodenaufruf pro Abfrage verwendet.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Eine Map gruppiert Notizen nach Projekt. Zwei Projekte müssen unabhängige Listen, wiederholte Notizen und die Eingangsreihenfolge behalten. Vorhandener Code erstellt eine gemeinsam genutzte ArrayList, speichert sie unter jedem neuen Schlüssel und fügt Notizen über get hinzu. Welche vollständige Korrektur erfüllt die Anforderungen?
  1. Die gemeinsame ArrayList behalten, aber jedes get durch getOrDefault mit derselben Liste ersetzen.
  2. Für jeden neuen Schlüssel eine eigene ArrayList erstellen und über ihre gespeicherte Referenz anhängen.
  3. Für jeden neuen Schlüssel ein eigenes HashSet erstellen und Notizen über seine gespeicherte Referenz hinzufügen.
  4. Für jeden eingehenden Datensatz eine neue leere ArrayList für das Projekt erstellen und die aktuelle Notiz anhängen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein Dokumentensystem braucht eindeutige Schlagwörter in der Reihenfolge ihres ersten Auftretens, direkten Objektzugriff über eine eindeutige Dokumenten-ID und einen separaten geordneten Verlauf, der wiederholte Besuche behält. Welche Strukturen passen zu den drei Anforderungen?
  1. TreeSet für Schlagwörter; List für ID-Zugriff; HashSet für den Verlauf.
  2. HashSet für Schlagwörter; Map für ID-Zugriff; TreeSet für den Verlauf.
  3. LinkedHashSet für Schlagwörter; Set für ID-Zugriff; Map mit Dokumenten-ID als Schlüssel für den Verlauf.
  4. LinkedHashSet für Schlagwörter; Map für ID-Zugriff; List für den Verlauf.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe

Schlüsselbegriffe

70 Schlüsselbegriffe, jeweils mit Definition

A

Abschneiden
Abschneiden verwirft bei der expliziten Umwandlung eines Werts in int den Nachkommateil und kann dadurch eine kleine Vergleichsdifferenz ungleich null zu null machen.
Die explizite Umwandlung der Preisdifferenz zwischen 2,7 und 2,2 in int ergibt einen falschen Gleichstand statt eines positiven Vergleichsergebnisses.
Array
Ein Array speichert eine feste Anzahl indexierter Elemente eines Typs und kann primitive Werte direkt ohne Wrapper-Typargumente enthalten.
Ein double[12] kann für jeden Monat einen Platz für seine Niederschlagsmessung in Millimetern bieten.
Aufbauaufwand
Der Aufbauaufwand ist die Arbeit, die zum Erstellen einer unterstützenden Struktur nötig ist, bevor spätere Operationen von ihrer Verwendung profitieren können.
Eine Menge für Zugehörigkeitsprüfungen sollte vor vielen Prüfungen einmal erstellt werden; ihr Aufbau gehört zum Gesamtaufwand.
Auswahl einer Collection
Bei der Auswahl einer Collection werden benötigte Positionen, Duplikate, Schlüsselzugriffe und Reihenfolge mit einem Interface und einer geeigneten Implementierung abgestimmt.
Ein alphabetischer Bericht über Anzahlen und eine geordnete Wiedergabeliste brauchen verschiedene Strukturen, weil sie unterschiedliche Informationen erhalten.
Autoboxing
Autoboxing ist Javas automatische Umwandlung eines primitiven Werts in das zugehörige Wrapperobjekt, wenn ein Objekt benötigt wird.
Wird das Literal 12 in eine Map mit Integer-Werten eingefügt, wandelt Java die Zahl zum Speichern automatisch in ein Wrapperobjekt um.

C

Collection
Collection ist das gemeinsame Java-Interface für Gruppen von Elementen; List und Set erweitern es, während das Interface Map davon getrennt ist.
Eine Methode zum Zählen von Wörtern, die nur liest, kann eine Collection<String> annehmen und entweder eine Liste oder eine Menge durchlaufen.
Collection-Sicht
Eine Collection-Sicht stellt einen Teil einer anderen Struktur über ein Collection-Interface bereit, wobei Änderungen mit der zugrunde liegenden Struktur verbunden sind.
Das Entfernen eines Produkts über die Schlüsselmenge der Bestands-Map entfernt den entsprechenden Eintrag aus der Map selbst.
Comparable
Comparable ist das Java-Interface, über das eine Klasse ihre natürliche Ordnung durch die Implementierung einer typisierten Methode compareTo definiert.
Eine Mitgliederklasse kann Comparable<Member> implementieren, sodass eine Listensortierung ihre Instanzen nach Körpergröße ordnen kann.
Comparator
Ein Comparator ist ein Objekt, das eine Vergleichsregel bereitstellt, die von der natürlichen Ordnung einer Klasse abweichen kann, etwa eine umgekehrte Ordnung oder eine ohne Beachtung der Groß- und Kleinschreibung.
String.CASE_INSENSITIVE_ORDER sortiert eine Liste, ohne die in jedem String gespeicherte Groß- und Kleinschreibung zu ändern.
compareTo
Die Methode compareTo gibt eine negative Ganzzahl, null oder eine positive Ganzzahl zurück, um dieses Objekt vor, gleichauf mit oder nach einem anderen einzuordnen.
Ein Ergebnis von -8 setzt das linke Objekt ebenso vor das rechte wie ein Ergebnis von -1.

D

Deklarierter Typ
Der deklarierte Typ einer Variablen bestimmt, welche Methoden der Compiler über diese Variable erlaubt, selbst wenn ihr Objekt zusätzliche Methoden hat.
Eine in einer List-Variablen gespeicherte ArrayList kann ensureCapacity über diese Variable nicht zugänglich machen.
Diamant-Syntax
Die Diamant-Syntax verwendet leere spitze Klammern bei einem Konstruktor, damit Java seine Typargumente aus der umgebenden Deklaration ableiten kann.
In HashMap<String, Integer> m = new HashMap<>(); vermeidet der Diamant die Wiederholung der beiden Typen.
Differenzmenge
Eine Differenzmenge enthält Elemente der ersten Menge, die in der zweiten fehlen; beim Vertauschen der Mengen kann sich daher das Ergebnis ändern.
Das Entfernen der Teilnehmenden vom Dienstag aus einer Montagskopie findet Personen, die nur am Montag teilgenommen haben, nicht solche, die nur am Dienstag teilgenommen haben.
Doppeltes Auftreten
Ein doppeltes Auftreten ist ein Eingabevorkommen, dessen gleicher Wert bereits gesehen wurde; eine Menge gesehener Werte erkennt es, wenn add false zurückgibt.
In der Folge 6, 9, 2, 9, 6 ist die zweite 9 der erste Eintrag, der einen früheren Wert wiederholt.

E

Eindeutiger Identifikator
Ein eindeutiger Identifikator unterscheidet jedes Objekt innerhalb der indexierten Daten und verhindert, dass separate Datensätze um denselben Map-Schlüssel konkurrieren.
Eine Mitglieder-ID hält zwei Personen mit demselben Anzeigenamen in separaten Einträgen eines Mitgliedersuchindex.
Eindeutiges Element
Ein eindeutiges Element ist ein Wert, der nach der Vergleichsregel der Collection als verschieden gilt, unabhängig davon, wie oft dieser Wert vorkommt.
Eine Häufigkeits-Map für "sun rain sun" enthält zwei unterschiedliche Wortschlüssel, erfasst aber drei Vorkommen.

F

Flache Kopie
Eine flache Kopie erzeugt eine separate Collection-Struktur mit denselben Elementreferenzen, statt die gespeicherten Objekte zu duplizieren.
Das Entfernen eines Buchs aus einer kopierten Liste lässt die Ausgangsliste unverändert, aber beide Listen können weiterhin auf dasselbe Buch verweisen.

G

Ganzzahlüberlauf
Ein Ganzzahlüberlauf tritt auf, wenn ein arithmetisches Ergebnis den int-Wertebereich überschreitet und umläuft, was Vergleichen durch Subtraktion das falsche Vorzeichen geben kann.
Der Vergleich extremer int-Felder mit Integer.compare vermeidet die Vorzeichenumkehr, die eine Subtraktion verursachen kann.
Gemeinsam genutzte Referenz
Eine gemeinsam genutzte Referenz ermöglicht zwei Variablen oder Einträgen den Zugriff auf dasselbe Objekt, sodass eine Änderung des Objekts über beide Referenzen sichtbar ist.
Zwei Kursschlüssel, denen ein Listenobjekt zugewiesen wurde, zeigen beide eine Person, die nur über einen dieser Schlüssel hinzugefügt wurde.
getOrDefault
Die Methode getOrDefault gibt den einem Schlüssel zugeordneten Wert oder den angegebenen Standardwert zurück, wenn keine Zuordnung für diesen Schlüssel existiert.
Das Lesen einer fehlenden Anzahl mit null als Standardwert ergibt 0, ohne einen neuen Eintrag in der Zähl-Map zu erzeugen.
Gruppierung
Gruppierung sammelt Elemente mit einer gemeinsamen Eigenschaft unter einem Map-Schlüssel und verwendet eine Liste oder Menge als Wert für die jeweilige Gruppe.
Ein Kursschlüssel kann zu einer Liste von Lernenden führen, ein Anfangsbuchstabe zu passenden Wörtern.

H

Hashcode-Vertrag
Der Hashcode-Vertrag verlangt, dass laut equals gleiche Objekte gleiche Hashcodes zurückgeben, und erlaubt zugleich Kollisionen bei ungleichen Objekten.
Koordinatenschlüssel verwenden dieselben Felder x und y sowohl in ihrer Gleichheitsprüfung als auch in ihrer Hashcode-Methode.
HashMap
Eine HashMap ist eine modifizierbare Java-Map, die eindeutige Schlüssel mit zugeordneten Werten speichert und keine bestimmte Iterationsreihenfolge garantiert.
Eine HashMap<String, Integer> kann die aktuelle Anzahl eines Produkts abrufen, ohne eine Listenposition zu verwenden.
HashSet
Ein HashSet ist eine modifizierbare Java-Menge mit durchschnittlich konstanter Laufzeit grundlegender Operationen bei geeigneter Hashcode-Berechnung und ohne garantierte Iterationsreihenfolge.
Ein HashSet<String> kann bereits verarbeitete Namen verfolgen, während ein Programm eine längere Eingabefolge liest.
Häufigkeitstabelle
Eine Häufigkeitstabelle verbindet jedes unterschiedliche Element mit seiner Anzahl an Vorkommen, häufig mit Map-Schlüsseln für Elemente und Ganzzahlwerten für Anzahlen.
Eine Wortzähl-Map unterscheidet die Anzahl verschiedener Wörter von der Gesamtzahl der Wortvorkommen.

I

Implementierung
Eine Implementierung ist eine konkrete Klasse, die die Operationen eines Interfaces bereitstellt und das Verhalten des erzeugten Objekts bestimmt.
HashMap und TreeMap implementieren beide Map, garantieren aber Unterschiedliches für die Schlüsselreihenfolge.
In-place-Sortierung
Eine In-place-Sortierung ordnet die übergebene Liste selbst um, statt eine separate sortierte Liste für eine Zuweisung durch den Aufrufer zurückzugeben.
Nach Collections.sort(values) zeigt die vorhandene Listenvariable ihre Elemente in der neuen Reihenfolge.
Inhaltliche Gleichheit
Inhaltliche Gleichheit behandelt separate Objekte als gleich, wenn ihre ausgewählten Daten übereinstimmen; dafür wird equals(Object) passend überschrieben.
Zwei getrennt erzeugte Koordinatenschlüssel können dieselbe Bezeichnung finden, wenn ihre Gleichheitsmethode beide Koordinaten vergleicht.
Interface
Ein Interface deklariert Operationen, die implementierende Klassen bereitstellen, sodass eine Variable oder ein Parameter die benötigten Fähigkeiten angeben kann.
Eine Methode, die List<String> annimmt, kann eine ArrayList oder eine LinkedList erhalten, ohne ihre Signatur zu ändern.
Iterationsreihenfolge
Die Iterationsreihenfolge ist die Folge, in der eine Traversierung Elemente oder Einträge besucht; manche Implementierungen garantieren eine solche Reihenfolge, andere nicht.
Eine Suche nach Punktzahlen mit Gleichstand braucht eine ausdrückliche Regel, wenn ihr Ergebnis von der HashMap-Traversierung unabhängig sein muss.
Iterator
Ein Iterator verfolgt eine Traversierung durch eine Collection und stellt Methoden bereit, um zu prüfen, ob ein nächstes Element existiert, und es abzurufen.
Eine Schleife zum Bereinigen des Bestands verwendet hasNext(), next() und das remove() des Iterators, um Mengen mit dem Wert null zu löschen.

K

Kapselung
Kapselung hält Daten innerhalb einer Klasse und stellt kontrollierte Methoden bereit, damit die Klasse Regeln für Aktualisierung und Zugriff einhalten kann.
Eine Bibliotheksklasse kann ihre Suchindizes privat halten, sodass ihre Methode addBook sie gemeinsam aktualisiert, statt dass Aufrufer sie bearbeiten.
Konsistenz mit equals
Konsistenz mit equals bedeutet, dass der Vergleich genau dann null zurückgibt, wenn die Gleichheitsprüfung true zurückgibt, sodass beide Regeln dieselben Werte als gleich erkennen.
Ein TreeSet braucht einen Mitgliedervergleich, der dieselben Identitäten unterscheidet wie die Gleichheitsregel der Mitglieder.
Konstante Laufzeit
Konstante Laufzeit beschreibt Arbeit, die ungefähr unabhängig von der Elementanzahl bleibt; grundlegende hashbasierte Operationen haben bei geeigneter Hashcode-Berechnung im Durchschnitt diesen Aufwand.
Das Lesen einer Position in einer ArrayList erfordert nicht das Durchsuchen aller früheren Positionen dieser Liste.

L

Laufende Summe
Eine laufende Summe ist ein angesammelter Betrag, der aktualisiert wird, indem jeder neue Beitrag zum bereits gespeicherten Betrag addiert wird.
Eine Ausgaben-Map liest die alte Kategoriesumme, addiert den nächsten Betrag und speichert das erhöhte Ergebnis.
Lineare Laufzeit
Lineare Laufzeit beschreibt Arbeit, die proportional zur Anzahl der Elemente wachsen kann, etwa wenn eine Suche die gesamte Collection prüfen muss.
Wiederholte Zugehörigkeitsprüfungen anhand einer langen Liste können immer wieder das Durchsuchen derselben gespeicherten Namen erfordern.
LinkedHashMap
Eine LinkedHashMap ist eine Map, deren gewöhnliche Form mit Einfügereihenfolge Schlüssel in dieser Reihenfolge besucht und dabei die üblichen Map-Operationen bietet.
Das Ersetzen eines gespeicherten Preises erhält den Platz dieses Produkts in einer LinkedHashMap mit Einfügereihenfolge.
LinkedHashSet
Ein LinkedHashSet speichert unterschiedliche Elemente und erhält ihre Einfügereihenfolge, einschließlich der Reihenfolge der ersten Vorkommen beim Kopieren aus einer Liste.
Eine in ein LinkedHashSet kopierte Schlagwortliste verliert Wiederholungen und behält die Reihenfolge, in der Schlagwörter erstmals erschienen.
List
Eine List speichert Elemente in einer bei null beginnenden indexierten Folge, erlaubt Duplikate und vergleicht Gleichheit anhand der vollständigen Elementreihenfolge.
Eine Wiedergabeliste verwendet Listenpositionen, um zwei Vorkommen desselben Lieds an verschiedenen Stellen der Folge zu behalten.
Logarithmische Laufzeit
Logarithmische Laufzeit beschreibt Arbeit, die mit der Elementanzahl langsam wächst, wie beim garantierten Aufwand grundlegender Zugriffe in TreeMaps und TreeSets.
Eine TreeMap hält Schlüssel sortiert und vermeidet zugleich bei jedem gewöhnlichen Schlüsselzugriff eine vollständige Suche.

M

Map
Eine Map ordnet eindeutigen Schlüsseln Werte zu und erlaubt wiederholte Werte, während jeder Schlüssel zu einem Zeitpunkt höchstens einen zugeordneten Wert hat.
Zwei Produkten kann jeweils der Preis 3,50 zugeordnet sein, ohne die Anforderung eindeutiger Schlüssel zu verletzen.
Map.Entry
Ein Map.Entry stellt eine Schlüssel-Wert-Zuordnung dar und ermöglicht während der Map-Traversierung den gemeinsamen Zugriff auf Schlüssel und Wert.
Eine Schleife über Einträge kann den Namen und die Punktzahl einer spielenden Person ausgeben, ohne die Punktzahl erneut über den Namen abzurufen.
Menge (Set)
Eine Menge ist eine Collection unterschiedlicher Elemente, die Zugehörigkeitsoperationen ohne die indexierten Positionen einer Liste bietet.
Eine Menge besuchter Städte behält einen Eintrag pro Stadt, selbst wenn eine reisende Person mehrfach zurückkehrt.
Mengenzugehörigkeit
Mengenzugehörigkeit beschreibt, ob ein Wert zu einer Menge gehört; contains prüft dies anhand der Vergleichsregel der Menge.
Ein Programm zur Prüfung von Benutzernamen prüft die Mengenzugehörigkeit, bevor es einen neuen Namen in die Menge vergebener Namen aufnimmt.
Methodenüberladung
Eine Methodenüberladung ist eine Methode, die denselben Namen wie eine andere Methode, aber andere Parameter hat, sodass Java eine andere Operation wählen kann.
Bei einer Ganzzahlliste wählt remove(1) das Entfernen nach Index, während remove(Integer.valueOf(1)) das Entfernen nach Wert wählt.

N

Nachschlagetabelle
Eine Nachschlagetabelle ordnet Codes oder Namen Daten zu, die ein Programm bei der Bearbeitung einer anderen Aufgabe abruft.
Ein Bestellrechner liest Produktpreise aus einer Tabelle, bevor er den Beitrag jedes Produkts addiert.
Natürliche Ordnung
Eine natürliche Ordnung ist der von einer Klasse bereitgestellte Standardvergleich, etwa die aufsteigende Zahlenordnung oder die zeichenbasierte String-Ordnung.
Beim Sortieren der Strings "20" und "3" steht "20" zuerst, weil die Anfangszeichen ihre Reihenfolge entscheiden.
Nicht modifizierbare Collection
Eine nicht modifizierbare Collection lehnt strukturelle Änderungen oder das Ersetzen über ihre Schnittstelle ab, während die enthaltenen Objekte veränderlich sein können.
Eine Liste aus List.of muss vor dem Sortieren kopiert werden, aber ein gespeichertes veränderliches Objekt wird durch diese Liste nicht unveränderlich.

P

Parallele Listen
Parallele Listen speichern zusammengehörige Felder an übereinstimmenden Indizes in separaten Listen, sodass die Beziehung von abgestimmten strukturellen Änderungen abhängt.
Wird der Name einer Person entfernt, ohne die Nummer am selben Index zu entfernen, stimmen spätere Telefonbucheinträge nicht mehr überein.
Parameter mit Interface-Typ
Ein Parameter mit Interface-Typ nimmt Objekte über die von einem Interface zugesicherten Operationen an, statt eine konkrete Implementierung zu verlangen.
Eine Berichtsmethode kann Map<String, Integer> annehmen, während Aufrufer eine HashMap oder TreeMap für die Speicherung wählen.
putIfAbsent
Die Methode putIfAbsent speichert einen Wert, wenn für einen Schlüssel keine Zuordnung zu einem Wert ungleich null besteht, und behält andernfalls den bereits zugeordneten Wert.
Vor dem Hinzufügen eines gruppierten Elements kann putIfAbsent sicherstellen, dass sein Schlüssel eine Liste hat, ohne eine vorhandene zu ersetzen.

R

Referenzgleichheit
Referenzgleichheit behandelt Objekte nur dann als gleich, wenn sie dieselbe Instanz sind; diese Gleichheit wird von Object geerbt.
Ohne Überschreibungen stimmt ein neu konstruierter Punkt nicht mit einem gespeicherten Punkt mit identischen Koordinaten überein.

S

Schlüssel-Wert-Paar
Ein Schlüssel-Wert-Paar verbindet in einer Map einen identifizierenden Schlüssel mit einem zugehörigen Wert, etwa einen Produktcode mit einer Anzahl.
In einer Bestands-Map verbindet das Paar "pen" → 18 einen Produktnamen mit der aktuell verfügbaren Anzahl.
Schlüsselbasierter Zugriff
Ein schlüsselbasierter Zugriff findet einen Wert über einen separaten Identifikator und macht eine Map nützlich, wenn wiederholte Suchen andernfalls Objektfelder prüfen müssten.
Eine Map mit Produktcodes beantwortet Preisabfragen direkt, während eine Liste nach dem passenden Code durchsucht werden müsste.
Schlüsselnormalisierung
Schlüsselnormalisierung wendet vor dem Speichern und Abrufen eine einheitliche Bereinigungsregel an, damit gleichwertige Eingabeformen denselben Map-Schlüssel verwenden.
Ein Wortzähler kann Token in Kleinbuchstaben umwandeln und Satzzeichen entfernen, bevor er jedes Vorkommen zu seiner Map hinzufügt.
Schnittmenge
Die Schnittmenge zweier Mengen enthält nur die Elemente, die beiden gemeinsam sind; retainAll entfernt nicht gemeinsame Werte aus der aufrufenden Menge.
Bleiben in einer Kopie der Montagsmenge nur die Namen vom Dienstag erhalten, findet man die Personen, die an beiden Tagen teilgenommen haben.
Sekundäres Vergleichskriterium
Ein sekundäres Vergleichskriterium ist ein weiterer Vergleich, der nur bei einem Gleichstand früherer Vergleichsfelder verwendet wird und so deren Vorrang in der Gesamtordnung erhält.
Ein Filmvergleich nach Jahr und dann nach Titel berücksichtigt Titel nur bei Filmen, die im selben Jahr erschienen sind.
Stabile Sortierung
Eine stabile Sortierung erhält die relative Eingabereihenfolge von Elementen, die nach dem für diese Sortierung verwendeten Vergleich gleich sind.
Zwei Spielende mit gleicher Punktzahl bei einem Vergleich nur nach Punktzahl bleiben nach einer stabilen Listensortierung in ihrer früheren relativen Reihenfolge.
Strukturelle Änderung
Eine strukturelle Änderung verändert die Schlüsselmenge einer Map, etwa wenn eine neue Zuordnung hinzugefügt oder eine vorhandene entfernt wird.
Das Ersetzen der Mengenangabe für einen bereits vorhandenen Schlüssel ändert dessen Wert, ohne die Map strukturell zu ändern.
Suchindex
Ein Suchindex ist eine Map von einem identifizierenden Schlüssel zu einem Objekt und ermöglicht den Zugriff über diesen Schlüssel, ohne wiederholt eine Objektliste zu durchsuchen.
Der ISBN-Suchindex einer Bibliothek kann dasselbe Buchobjekt zurückgeben, das auch in ihrer Liste aller Bücher erscheint.

T

Teilmenge
Eine Teilmenge hat jedes ihrer Elemente in einer anderen Menge, die zusätzliche Elemente enthalten darf; a.containsAll(b) prüft, ob b in a enthalten ist.
Eine ausgewählte Gruppe ist eine Teilmenge einer Teilnehmermenge, wenn jede ausgewählte Person auf der Liste dieser Veranstaltung steht.
Transitivität
Transitivität verlangt von einer Ordnung, a vor c zu setzen, wenn sie a vor b und b vor c setzt, und hält Vergleiche damit schlüssig.
Der Vergleich von Feldern in einer festen Prioritätsreihenfolge vermeidet einen Zyklus, in dem jedes von drei Objekten vor einem anderen steht.
TreeMap
Eine TreeMap hält Zuordnungen nach ihren Schlüsseln geordnet und verwendet den Schlüsselvergleich, um bei einem Zugriff oder einer Ersetzung eine vorhandene Zuordnung zu erkennen.
Für die alphabetische Ausgabe von Wortanzahlen kann eine TreeMap verwendet werden, deren kleinster Schlüssel über firstKey() verfügbar ist.
TreeSet
Ein TreeSet hält Elemente sortiert und entscheidet anhand seines Vergleichsergebnisses, ob ein Element bereits in der Menge vorhanden ist.
Ein Mitgliedervergleich nur nach Körpergröße lässt zwei verschiedene Mitglieder gleicher Größe um eine Position in der Menge konkurrieren.

U

Unboxing
Unboxing ist Javas automatische Umwandlung eines Wrapperobjekts in einen primitiven Wert; der Versuch mit null löst eine Ausnahme aus.
Die Zuweisung eines fehlenden Integer-Suchergebnisses an einen int schlägt fehl, weil das zurückgegebene null nicht per Unboxing umgewandelt werden kann.

V

Veränderlicher Schlüssel
Ein veränderlicher Schlüssel hat Daten, die geändert werden können; das Ändern von Feldern, die für Gleichheit oder Hashcode verwendet werden, kann während seiner Speicherung den Map-Zugriff beeinträchtigen.
Ein Koordinatenschlüssel ist mit final-Feldern sicherer als mit Settern, die seine gespeicherte Identität ändern können.
Vereinigungsmenge
Die Vereinigungsmenge zweier Mengen enthält jedes Element, das in mindestens einer der beiden Mengen vorhanden ist; Javas addAll bildet sie, indem es die aufrufende Menge ändert.
Eine Kopie der Montagsmenge mit den Teilnehmenden vom Dienstag zu ergänzen, ergibt alle Personen, die an mindestens einem Tag da waren.
Verschachtelte Collection
Eine verschachtelte Collection speichert Collections innerhalb einer anderen Struktur, sodass äußere Schlüssel und innere Mitglieder getrennten Regeln folgen können.
Eine sortierte Kurs-Map kann Teilnehmerlisten in Einfügereihenfolge enthalten, ohne die Lernenden selbst zu sortieren.

W

Wrapperklasse
Eine Wrapperklasse stellt einen Objekttyp für einen primitiven Wert bereit, sodass Zahlen und andere primitive Daten als Collection-Typargumente verwendet werden können.
Eine Map für Mengenangaben verwendet Integer als Werttyp, weil int nicht als generisches Typargument auftreten kann.

Z

Zeichenordnung
Die Zeichenordnung vergleicht Strings anhand ihrer ersten unterschiedlichen UTF-16-Codeeinheit; ein kürzeres übereinstimmendes Präfix wird zuerst eingeordnet.
In den Beispielen "7", "Bee" und "ant" setzt die natürliche String-Ordnung die Ziffer vor die Buchstaben.

Über diese Einheit

Von StudeliFehler melden

Erstelle deine eigenen Lernmaterialien

Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.

Jetzt starten