- Lernen
- Informatik & Informationswissenschaften
- Programmierung
- Java-Programmierung – Klassen, Vererbung, Collections und Streams
- HashMaps und Collections in Java
HashMaps und Collections in Java
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
- 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 sieDeklariere 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 SchleifenDurchlaufe 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üsselSorge 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.
- Erstelle eine HashMap, füge Einträge ein, rufe sie ab, ändere und entferne sie
- 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üsselErstelle 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-WerteErstelle 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 abVerwende Maps als Nachschlagetabellen und Suchindizes, die Objekte über einen eindeutigen Schlüssel finden, verwalte sie innerhalb einer Klasse und halte mehrere Suchindizes konsistent.
- Zähle Vorkommen und berechne Summen je Schlüssel
- 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 HashSetFü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 ReihenfolgeBerechne 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.
- Speichere Werte ohne Duplikate und prüfe ihre Mengenzugehörigkeit mit HashSet
- 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-TypenErklä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 MapVergleiche die Garantien der drei Interfaces, erkenne ihre wichtigsten Implementierungen und arbeite mit nicht modifizierbaren Collections, die mit of erzeugt werden.
- Deklariere Variablen und Parameter mit Interface-Typen
- 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 StringsSortiere 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 KlasseGib 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 MapsOrdne Objekte nach mehreren Feldern, halte compareTo konsistent mit equals und verwende TreeSet und TreeMap, um Daten sortiert zu halten.
- Sortiere Listen mit Zahlen und Strings
- 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-OperationenSchä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 passtBeantworte einige Fragen zu Reihenfolge, Duplikaten und Zugriff, um zwischen Arrays, Listen, Mengen und Maps zu wählen, und kombiniere sie für komplexere Daten.
- Vergleiche den Aufwand gängiger Collection-Operationen
HashMaps und Collections in Java einfach erklärt
1Speichere 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.
putersetzt einen vorhandenen Wert und gibt den vorherigen Wert zurück.- Ein
getfür einen fehlenden Schlüssel liefertnull; das Unboxing löst eineNullPointerExceptionaus. getOrDefaultliefert 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,valuesoderentrySet. HashMaphat keine garantierte Iterationsreihenfolge; löse Gleichstände ausdrücklich auf.- Verwende das
removeeines 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)undhashCode()anhand passender Felder. @Overrideerkennt eine versehentliche Überladung vonequals.- Ändere die für Gleichheit und Hashcode relevanten Felder nicht, während ein Schlüssel gespeichert ist.
2Zä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.
getgibt die gespeicherte Referenz zurück, sodass Änderungen an der inneren Collection kein zusätzlichesputbrauchen.- 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.
3Speichere 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
HashSetspeichert Werte ohne Duplikate, ohne Index und ohne garantierte Reihenfolge.addgibt 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.
| Frage | Methode auf einer Kopie von Montag | Ergebnis |
|---|---|---|
| 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
| Implementierung | Reihenfolge beim Besuch der Elemente |
|---|---|
HashSet | Keine Garantie |
LinkedHashSet | Einfügereihenfolge |
TreeSet | Sortierte 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,retainAllundremoveAlländern die aufrufende Menge.- Kopiere eine Menge zuerst, wenn ihre ursprünglichen Elemente noch gebraucht werden.
containsAllprü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.
4Programmiere 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.
ListundSeterweiternCollection;Mapstellt 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
| Interface | Was es speichert | Wichtige Regel |
|---|---|---|
List | Elemente an Positionen ab 0 | Wiederholte Elemente sind erlaubt |
Set | Unterschiedliche Elemente | Keine indexbasierte get-Operation |
Map | Schlüssel-Wert-Paare | Schlü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.oflehnt doppelte Elemente ab;Map.oflehnt doppelte Schlüssel ab.- Eine modifizierbare Kopie hat eine separate Collection-Struktur, teilt sich aber die Elementreferenzen.
5Sortiere 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 gibtvoidzurü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.
minundmaxfinden 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 MethodecompareTo. - Negative, null und positive Ergebnisse bedeuten davor, gleichgestellt und danach.
- Verwende
Integer.compareundDouble.comparefü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
equalsverlangt genau dann ein Vergleichsergebnis von null, wenn Gleichheit vorliegt. TreeMapsortiert 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.
6Wä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.
| Collection | Operation | Aufwand |
|---|---|---|
ArrayList | get(i), set(i, x) | Konstant |
ArrayList | Am Ende anhängen | Im Durchschnitt konstant |
ArrayList | contains, indexOf, Entfernen nach Wert | Linear |
ArrayList | Nahe am Anfang einfügen oder entfernen | Linear |
HashMap / HashSet | Einfacher Schlüsselzugriff oder Prüfung der Zugehörigkeit, Einfügen, Entfernen | Im Durchschnitt konstant bei gut verteilten Hashcodes |
TreeMap / TreeSet | Einfacher Zugriff, Einfügen, Entfernen | Logarithmisch |
LinkedList | An einem der beiden Enden hinzufügen oder entfernen | Konstant |
LinkedList | get(i) im Allgemeinen | Linear |
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.
ArrayListbietet 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 Bedarf | Ausgangswahl | Beispiel |
|---|---|---|
| Einen Wert über einen separaten Schlüssel finden | Map | Produktcode zu Preis |
| Zugehörigkeit ohne Duplikate prüfen | Set | Vergebene Benutzernamen |
| Positionen, Reihenfolge oder wiederholte Elemente behalten | List | Eine Wiedergabeliste mit wiederholten Liedern |
| Eine feste Anzahl von Plätzen verwalten | Array | Zwö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
1Verfolge eine Bestands-Map vom Speichern bis zum Abruf
13 Schritte
- 1Einfü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.
- 2ErklärungErstelle eine Zuordnung pro Schlüssel
Erstelle
HashMap<String, Integer> stock = new HashMap<>();.Stringbeschreibt die Schlüssel;Integerbeschreibt die Werte. Die Map verwendet Referenztypen, daher kannintnicht das Werttypargument sein. Java wandelt ein Literal wie6in ein Wrapperobjekt um, wennstock.put("folder", 6)es speichert. Der Diamant rechts lässt Java die beiden Typen ableiten. - 3BeispielErsetze 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
8und gibt6inoldzurü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. - 4HerausforderungLies, ohne einzufügen
Welche Werte haben
nundstock.size()nach diesem Lesezugriff? Die Map enthält weiterhin folder 8 und clip 11.int n = stock.getOrDefault("tape", 0);---reveal---
nist0, und die Größe bleibt2. Der Standardwert ist ein Ergebnis für einen fehlenden Schlüssel, kein eingefügter Eintrag. Ein Lesezugriff mitget("tape")liefert stattdessen null, das nicht per Unboxing in einenintumgewandelt werden kann. - 5Erklä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 separatesgetanzeigen. Wird nur eine Summe benötigt, durchlaufestock.values()und addiere die Mengen; wiederholte Mengen tragen weiterhin einzeln zur Summe bei. - 6KernaussageGehe 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
LinkedHashMapfür Einfügereihenfolge oderTreeMapfür sortierte Schlüssel und lege bei gleichen Maximalwerten eine ausdrückliche Regel fest, wenn der Gewinner vorhersagbar sein muss. - 7BeispielLö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.removewährend einer for-each-Traversierung kann dagegenConcurrentModificationExceptionauslösen. - 8HerausforderungErstelle eine separate Schlüsselkopie
Vor dem Bereinigen wird
keysmitnew ArrayList<>(stock.keySet())erstellt. Was geschieht mit der Bestands-Map, wennkeys.remove("folder")aufgerufen wird?---reveal---
Die Map behält ihre Zuordnung für folder.
keysist eine separate Liste der Schlüssel, die beim Kopieren vorhanden waren. Das Entfernen ausstock.keySet()selbst würde den Map-Eintrag entfernen, weil dieses Objekt eine verbundene Sicht ist. - 9BeispielProbiere einen eigenen Schlüssel aus
Angenommen,
Binhat die Felderrowundcolumnund keine Gleichheitsüberschreibungen. Speichere eine Bezeichnung mitnew Bin(3, 4)und rufe sie dann mit einem anderennew Bin(3, 4)ab. Der Zugriff liefert null. Das sind zwei verschiedene Objekte, und das geerbteObject.equalsverwendet Identität. Aus übereinstimmenden Feldwerten wurde noch keine Regel für übereinstimmende Schlüssel gemacht. - 10Erklä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 überschreibehashCode()anhand derselben Felder, etwa mitObjects.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. - 11HerausforderungErkenne eine Überladung
Eine Klasse definiert
public boolean equals(Bin other)undhashCode()anhand ihrer Koordinaten. Warum kann ein Zugriff mit einem separaten, gleich aussehenden Behälter trotzdem fehlschlagen?---reveal---
Der Parameter muss
Objectsein, um Javas Gleichheitsmethode zu überschreiben. Die Methode mit einem Bin-Parameter ist eine Überladung, sodass die geerbte Identitätsgleichheit bestehen bleibt. Ergänzt du@Overridebei dieser falschen Signatur, deckt der Compiler den Fehler auf. - 12HerausforderungKorrigiere 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.
- 13ZusammenfassungNutze 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.
2Erstelle Teilnahmeinformationen beim Eintreffen von Datensätzen
12 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungGewinne aus eingehenden Datensätzen nützliche Antworten
- 2BeispielBeginne die Zählung einer Sitzung
- 3BeispielUnterscheide Sitzungen von Datensätzen
- 4HerausforderungKorrigiere eine zurückgesetzte Anzahl
- 5ErklärungErstelle eine Gruppe einmal
- 6BeispielVerfolge die innere Referenz
- 7HerausforderungFinde den Fehler durch gemeinsam genutzte Gruppen
- 8ErklärungIndexiere über einen identifizierenden Schlüssel
- 9KernaussageÄndere ein Objekt an mehreren Stellen
- 10HerausforderungHalte das Entfernen konsistent
- 11HerausforderungKombiniere Anzahlen mit eindeutiger Mitgliedschaft
- 12ZusammenfassungPrüfe ein erstes und ein wiederholtes Eintreffen
3Vergleiche zwei Teilnahmegruppen
9 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungFrage nach den Personen, nicht nach der Anzahl der Besuche
- 2BeispielFasse wiederholte Erfassungen zusammen
- 3HerausforderungHalte beim ersten wiederholten Eintreffen an
- 4BeispielBehalte nur gemeinsame Mitglieder
- 5ErklärungWähle die Richtung der Differenz
- 6HerausforderungPrüfe eine ausgewählte Gruppe
- 7TippWähle eine nützliche Ausgabereihenfolge
- 8HerausforderungErstelle einen sortierten Bericht über fehlende Teilnehmende
- 9ZusammenfassungLies die aufrufende Menge als Ausgangsgruppe
4Lies Collection-Deklarationen und Kopien
10 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungLies beide Seiten der Deklaration
- 2ErklärungDeklariere, was der Aufrufer braucht
- 3BeispielVerwende zum Lesen einen allgemeineren Parameter
- 4HerausforderungUntersuche die fehlende Methode
- 5VerbindungWähle die Bedeutung der Inhalte
- 6BeispielVerfolge das Entfernen von Ganzzahlen
- 7HerausforderungKopiere vor dem Sortieren
- 8KernaussageUnterscheide Objektänderungen von Listenänderungen
- 9HerausforderungÜbergib die richtige Map-Sicht
- 10ZusammenfassungPrüfe Typ, Operation und Objekt
5Erstelle eine Rangliste mit den richtigen Gleichständen
15 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungWähle, was zuerst kommt
- 2BeispielSortiere dieselbe Liste
- 3ErklärungLies das erste unterschiedliche Zeichen
- 4HerausforderungVerwende eine bereitgestellte Ordnung
- 5ErklärungGib einer Klasse eine natürliche Ordnung
- 6BeispielVermeide einen falschen numerischen Gleichstand
- 7HerausforderungKehre das numerische Feld um
- 8BeispielLöse nur tatsächliche Gleichstände auf
- 9BeispielGehe die Rangliste durch
- 10HerausforderungSieh, was ein TreeSet behält
- 11KernaussageStimme Ordnung und Identität aufeinander ab
- 12VerbindungPrüfe den Schlüssel einer sortierten Map
- 13HerausforderungBehalte jedes Ergebnis in einer sortierten Rangliste
- 14TippSorge dafür, dass die Regel für Dreiergruppen funktioniert
- 15ZusammenfassungPrüfe einen Vergleich an zwei Stellen
6Wähle Strukturen für eine Kursteilnehmerliste
10 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungListe die Fragen des Programms auf
- 2BeispielErkenne die Suche innerhalb der Schleife
- 3ErklärungErstelle die Grundlage für Zugehörigkeitsprüfungen einmal
- 4HerausforderungVergleiche wachsende Eingaben
- 5BeispielBehalte wiederholte Einschreibungsdatensätze
- 6ErklärungWähle die äußere und innere Reihenfolge
- 7HerausforderungKorrigiere die falsche Duplikatregel
- 8TippBerücksichtige den Aufwand für die benötigte Ordnung
- 9HerausforderungKombiniere den fertigen Entwurf
- 10ZusammenfassungWähle das Verhalten vor der Geschwindigkeitsmessung
HashMaps und Collections in Java: Übungsaufgaben
Set 1: Lies und aktualisiere Maps zuverlässig10 Übungsfragen
Frage 1 von 10
HashMap<String, Integer> erhält put("brush", 5) und danach put("brush", 14). Wie groß ist sie und welchen Wert hat "brush"?Antwort zeigenAntwort ausblenden
put addiert die eingehende Anzahl nicht zur vorherigen. Zum Aufsummieren brauchst du einen Ausdruck, der den Wert liest und aktualisiert.Frage 2 von 10
"tray" nicht. Was geschieht bei der Ausführung von int n = map.get("tray");?Antwort zeigenAntwort ausblenden
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
Antwort zeigenAntwort ausblenden
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
equals-Methode gleich. Welche Hashcodes müssen sie haben?Antwort zeigenAntwort ausblenden
Frage 5 von 10
"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?Antwort zeigenAntwort ausblenden
put zurückgegebenen mit dem gespeicherten Wert.Frage 6 von 10
entrySet() und muss jeden Eintrag mit dem Wert null löschen. Wie soll sie den Eintrag während der Traversierung entfernen?Antwort zeigenAntwort ausblenden
ConcurrentModificationException auslösen. Das Ersetzen einer Mengenangabe durch eine Nullreferenz würde den Eintrag nicht löschen.Frage 7 von 10
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?Antwort zeigenAntwort ausblenden
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
Antwort zeigenAntwort ausblenden
Frage 9 von 10
"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?Antwort zeigenAntwort ausblenden
Frage 10 von 10
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?Antwort zeigenAntwort ausblenden
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
"north" → 4, "south" → 2 und "west" → 3. Wie viele unterschiedliche Schlüssel enthält sie?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
"cedar". Was gibt ein weiterer Aufruf von add("cedar") zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
"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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
C.removeAll(B) aus. Was enthält C?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
!seen.add(n) an. Welche Zahl wird ausgegeben?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
"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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
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)?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
Set<String> codes = new HashSet<>(); der deklarierte Typ von codes?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
a.compareTo(b) zurückgibt?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
List<Integer> beginnt als [4, 8, 12]. Sie führt remove(1) aus. Was bleibt übrig?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
"zebra", "Apron", "18", "3", "ant"?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
Collection<String> an. Ein Aufrufer hat Map<String, String> labels und möchte, dass die Methode jeden Bezeichnungswert verarbeitet. Was sollte übergeben werden?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
(int) (this.price - other.price) zurück. Was geht bei den Preisen 6,8 und 6,3 schief?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
compareTo als Nächstes tun?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
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?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
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
"pending", dem ausdrücklich null zugeordnet ist. Was gibt getOrDefault("pending", 20) zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Set.of("draft", "final", "draft")?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
"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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
Collections.reverse(list)?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
"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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
addAll(B) und dann removeAll(A) aus. Was ist U und wurde eines der Originale geändert?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
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
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
map.values()?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
get hinzu. Welche vollständige Korrektur erfüllt die Anforderungen?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe
Schlüsselbegriffe
A
Abschneiden
Array
double[12] kann für jeden Monat einen Platz für seine Niederschlagsmessung in Millimetern bieten.Aufbauaufwand
Auswahl einer Collection
Autoboxing
12 in eine Map mit Integer-Werten eingefügt, wandelt Java die Zahl zum Speichern automatisch in ein Wrapperobjekt um.C
Collection
Collection<String> annehmen und entweder eine Liste oder eine Menge durchlaufen.Collection-Sicht
Comparable
compareTo definiert.Comparable<Member> implementieren, sodass eine Listensortierung ihre Instanzen nach Körpergröße ordnen kann.Comparator
String.CASE_INSENSITIVE_ORDER sortiert eine Liste, ohne die in jedem String gespeicherte Groß- und Kleinschreibung zu ändern.compareTo
D
Deklarierter Typ
List-Variablen gespeicherte ArrayList kann ensureCapacity über diese Variable nicht zugänglich machen.Diamant-Syntax
HashMap<String, Integer> m = new HashMap<>(); vermeidet der Diamant die Wiederholung der beiden Typen.Differenzmenge
Doppeltes Auftreten
add false zurückgibt.E
Eindeutiger Identifikator
Eindeutiges Element
"sun rain sun" enthält zwei unterschiedliche Wortschlüssel, erfasst aber drei Vorkommen.F
Flache Kopie
G
Ganzzahlüberlauf
Integer.compare vermeidet die Vorzeichenumkehr, die eine Subtraktion verursachen kann.Gemeinsam genutzte Referenz
getOrDefault
Gruppierung
H
Hashcode-Vertrag
equals gleiche Objekte gleiche Hashcodes zurückgeben, und erlaubt zugleich Kollisionen bei ungleichen Objekten.x und y sowohl in ihrer Gleichheitsprüfung als auch in ihrer Hashcode-Methode.HashMap
HashMap<String, Integer> kann die aktuelle Anzahl eines Produkts abrufen, ohne eine Listenposition zu verwenden.HashSet
HashSet<String> kann bereits verarbeitete Namen verfolgen, während ein Programm eine längere Eingabefolge liest.Häufigkeitstabelle
I
Implementierung
HashMap und TreeMap implementieren beide Map, garantieren aber Unterschiedliches für die Schlüsselreihenfolge.In-place-Sortierung
Collections.sort(values) zeigt die vorhandene Listenvariable ihre Elemente in der neuen Reihenfolge.Inhaltliche Gleichheit
equals(Object) passend überschrieben.Interface
List<String> annimmt, kann eine ArrayList oder eine LinkedList erhalten, ohne ihre Signatur zu ändern.Iterationsreihenfolge
Iterator
hasNext(), next() und das remove() des Iterators, um Mengen mit dem Wert null zu löschen.K
Kapselung
addBook sie gemeinsam aktualisiert, statt dass Aufrufer sie bearbeiten.Konsistenz mit equals
Konstante Laufzeit
ArrayList erfordert nicht das Durchsuchen aller früheren Positionen dieser Liste.L
Laufende Summe
Lineare Laufzeit
LinkedHashMap
LinkedHashMap mit Einfügereihenfolge.LinkedHashSet
LinkedHashSet kopierte Schlagwortliste verliert Wiederholungen und behält die Reihenfolge, in der Schlagwörter erstmals erschienen.List
Logarithmische Laufzeit
M
Map
Map.Entry
Menge (Set)
Mengenzugehörigkeit
contains prüft dies anhand der Vergleichsregel der Menge.Methodenüberladung
remove(1) das Entfernen nach Index, während remove(Integer.valueOf(1)) das Entfernen nach Wert wählt.N
Nachschlagetabelle
Natürliche Ordnung
"20" und "3" steht "20" zuerst, weil die Anfangszeichen ihre Reihenfolge entscheiden.Nicht modifizierbare Collection
List.of muss vor dem Sortieren kopiert werden, aber ein gespeichertes veränderliches Objekt wird durch diese Liste nicht unveränderlich.P
Parallele Listen
Parameter mit Interface-Typ
Map<String, Integer> annehmen, während Aufrufer eine HashMap oder TreeMap für die Speicherung wählen.putIfAbsent
putIfAbsent sicherstellen, dass sein Schlüssel eine Liste hat, ohne eine vorhandene zu ersetzen.R
Referenzgleichheit
Object geerbt.S
Schlüssel-Wert-Paar
"pen" → 18 einen Produktnamen mit der aktuell verfügbaren Anzahl.Schlüsselbasierter Zugriff
Schlüsselnormalisierung
Schnittmenge
retainAll entfernt nicht gemeinsame Werte aus der aufrufenden Menge.Sekundäres Vergleichskriterium
Stabile Sortierung
Strukturelle Änderung
Suchindex
T
Teilmenge
a.containsAll(b) prüft, ob b in a enthalten ist.Transitivität
TreeMap
firstKey() verfügbar ist.TreeSet
U
Unboxing
Integer-Suchergebnisses an einen int schlägt fehl, weil das zurückgegebene null nicht per Unboxing umgewandelt werden kann.V
Veränderlicher Schlüssel
Vereinigungsmenge
addAll bildet sie, indem es die aufrufende Menge ändert.Verschachtelte Collection
W
Wrapperklasse
Integer als Werttyp, weil int nicht als generisches Typargument auftreten kann.Z
Zeichenordnung
"7", "Bee" und "ant" setzt die natürliche String-Ordnung die Ziffer vor die Buchstaben.- 1Java-Programme kompilieren und starten
- 2Bedingungen und Schleifen in Java
- 3Java-Methoden und Problemzerlegung
- 4Listen, Arrays und Strings in Java
- 5Java-Klassen und Objekte
- 6Objektreferenzen in Java
- 7HashMaps und Collections in Java
- 8Vererbung in Java
- 9Ausnahmen und Dateien in Java
- 10Modultests in Java
- 11Lambda-Ausdrücke und Streams in Java
Über diese Einheit
Erstelle deine eigenen Lernmaterialien
Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.