Eine Menge speichert eindeutige Werte
Ein HashSet (aus java.util) ist eine Sammlung, die jeden Wert höchstens einmal enthält. Es gibt keine Schlüssel und keine zugeordneten Werte wie in einer HashMap - nur einen Sack voll unterschiedlicher Elemente. Seine ganze Aufgabe ist es, eine Frage schnell zu beantworten: „Ist dieses Ding hier drin?"
Es gibt einen einzigen Typparameter, <ElementType>. Wie bei ArrayList und HashMap typisierst du die Variable üblicherweise mit der Schnittstelle Set und konstruierst ein HashSet.
add gibt zurück, ob der Wert neu war
add speichert den Wert nicht einfach nur - es gibt ein boolean zurück, das dir sagt, ob sich die Menge tatsächlich verändert hat. Einen bereits vorhandenen Wert hinzuzufügen gibt false zurück und lässt die Menge unverändert.
Dieser Rückgabewert ist wirklich nützlich: if (!seen.add(x)) { /* x ist eine Wiederholung */ } lässt dich Duplikate im Vorbeigehen in einer einzigen Zeile erkennen.
Duplikate aus einer Liste entfernen
Da eine Menge Wiederholungen ablehnt, ist der schnellste Weg, eine Sammlung zu deduplizieren, sie in eine Menge zu kippen. Der HashSet-Konstruktor akzeptiert jede andere Sammlung:
Das ist der häufigste Grund, warum Anfänger zu einer Menge greifen. Sei dir nur bewusst, dass du bei diesem Hin und Her die ursprüngliche Reihenfolge verlierst - verwende LinkedHashSet, wenn die Reihenfolge wichtig ist (weiter unten behandelt).
contains, remove und size
Die alltäglichen Operationen spiegeln die der anderen Sammlungen wider:
Der große Vorteil gegenüber einer ArrayList ist contains. Eine Liste muss jedes Element durchlaufen, um es zu beantworten (O(n)); ein HashSet springt fast direkt zur Antwort (etwa O(1)). Wenn du dich dabei ertappst, list.contains(...) innerhalb einer Schleife aufzurufen, ist das meist das Signal, auf eine Menge umzusteigen.
Mengenoperationen: Vereinigung, Schnittmenge, Differenz
Mengen glänzen, wenn du sie kombinierst. Die Methoden lesen sich fast wie normales Deutsch, sobald du weißt, welche welche ist:
Der entscheidende Stolperstein: addAll, retainAll und removeAll verändern die Menge, auf der sie aufgerufen werden. Deshalb kopiert jedes Beispiel zuerst a in ein frisches HashSet - sonst würdest du dein Original zerstören. Baue für jedes Ergebnis eine neue Menge.
HashSet behält die Reihenfolge nicht bei
Wie HashMap gibt ein HashSet keine Zusicherung über die Iterationsreihenfolge, und die Reihenfolge kann sich zwischen Durchläufen unterscheiden. Wenn du Vorhersagbarkeit brauchst:
LinkedHashSetbewahrt die Einfügereihenfolge - die Reihenfolge, in der du die Elemente hinzugefügt hast.TreeSethält die Elemente nach ihrer natürlichen Ordnung sortiert (oder nach einemComparator, den du angibst).
Alle drei implementieren die Schnittstelle Set, sodass der Wechsel zwischen ihnen eine einzeilige Änderung am Konstruktor ist.
Elemente müssen hashbar sein
Ein HashSet wird unter der Haube von einer HashMap getragen, daher gilt dieselbe Regel: Es findet Elemente, indem es sie hasht, was bedeutet, dass hashCode() und equals() eines Elements übereinstimmen müssen. Eingebaute Typen wie String und Integer machen das bereits richtig, weshalb die doppelten "java"-Strings oben korrekt zusammenfallen. Wenn du Instanzen deiner eigenen Klasse speicherst, überschreibe sowohl equals als auch hashCode - sonst werden zwei Objekte, die inhaltlich „gleich" sind, als verschieden behandelt, und contains sowie die Deduplizierung schlagen stillschweigend fehl.
Als Nächstes: Sammlungen durchlaufen
Du hast jetzt die drei Arbeitstier-Sammlungen kennengelernt - ArrayList, HashMap und HashSet. Jede durchläufst du ein wenig anders, und es gibt subtile Fallen (etwa eine Sammlung zu verändern, während du über sie iterierst). Als Nächstes fügen wir alles zusammen und behandeln, wie man Sammlungen sauber mit der for-each-Schleife, Iteratoren und forEach durchläuft.
Häufig gestellte Fragen
Wie erstellt man ein HashSet in Java?
Deklariere es mit einem einzigen Typparameter - dem Elementtyp - und rufe den Konstruktor auf: Set<String> tags = new HashSet<>();. Füge Werte mit tags.add("java"); hinzu und prüfe die Zugehörigkeit mit tags.contains("java");. Importiere java.util.HashSet und java.util.Set.
Was ist der Unterschied zwischen einem HashSet und einer ArrayList in Java?
Eine ArrayList behält jedes Element, das du hinzufügst (Duplikate eingeschlossen), in Einfügereihenfolge und wird über die Position indiziert. Ein HashSet speichert nur eindeutige Werte, gibt keine Zusicherung über die Reihenfolge, hat keinen Index, und seine contains-Prüfung läuft annähernd in konstanter Zeit, statt die ganze Liste zu durchsuchen. Greife zu einem HashSet, wenn es dir um Eindeutigkeit oder schnelle Zugehörigkeit geht, nicht um die Position.
Wie entfernt man Duplikate aus einer Liste in Java?
Übergib die Liste an den Konstruktor eines HashSet: Set<String> unique = new HashSet<>(list);. Die Menge verwirft wiederholte Werte automatisch. Wenn du eine Liste zurückbrauchst (und dir der Verlust der Reihenfolge egal ist), umhülle sie erneut: new ArrayList<>(unique). Verwende stattdessen ein LinkedHashSet, wenn die ursprüngliche Reihenfolge erhalten bleiben soll.