948 Stimmen

Wie initialisiert man HashSet-Werte durch Konstruktion?

Ich muss eine Set mit Anfangswerten.

Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");

Gibt es eine Möglichkeit, dies in einer einzigen Codezeile zu tun? Es ist zum Beispiel nützlich für ein endgültiges statisches Feld.

3 Stimmen

Für Java 8, Java 9 und Java 10 siehe meine Antwort stackoverflow.com/a/37406054/1216775

2 Stimmen

Die Antwort von Michael Berdyshev ist eigentlich die beste, weil sie die sauberste Art ist, eine abänderbar Set. i_am_zero Answer hat auch eine andere Möglichkeit, ein veränderbares Set zu erstellen, aber es ist ausführlicher/umständlicher [mit Lambda-Streaming]; ansonsten ist i_am_zero Answer die nächstbeste Lösung für die Breite seiner verschiedenen Optionen (über Java-Versionen hinweg).

0 Stimmen

HINWEIS: Einige Antworten lassen den Parameter `new HashSet<T>(int initialCapacity) weg, wenn Sie die Größe der Sammlung bereits kennen, verwenden Sie ihn.

1169voto

Gennadiy Punkte 17077

Es gibt eine Kurzschrift, die ich verwende, die nicht sehr zeitsparend ist, aber in eine einzige Zeile passt:

Set<String> h = new HashSet<>(Arrays.asList("a", "b"));

Auch dies ist nicht zeitsparend, da Sie ein Array konstruieren, es in eine Liste umwandeln und diese Liste zur Erstellung einer Menge verwenden.

Bei der Initialisierung von statischen Endsätzen schreibe ich das normalerweise so:

public static final String[] SET_VALUES = new String[] { "a", "b" };
public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES));

Etwas weniger hässlich und effizienter ist die statische Initialisierung.

2 Stimmen

Obwohl wahrscheinlich richtig zum Zeitpunkt des Schreibens, ab Java 7 verwenden Sie die Diamond-Operator wie in: Set<String> h = new HashSet<>(Arrays.asList("a", "b")); public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES));

0 Stimmen

Korrigiert für die Java-Diamanten-Notation, wie Sie erwähnt haben, aber ich hatte keine Zeit, es zu testen. Wenn jemand das überprüfen kann, wäre das großartig. Hauptanliegen ist die Hashset zu setzen Zuordnung, die HashSet Konstruktor kann eine explizite generischen Typ benötigen.

3 Stimmen

@Gennadiy Kann bestätigen, dass die Rautennotation gut funktioniert (sogar über die Set-Deklaration und HashSet-Zuweisung hinweg).

414voto

Bozho Punkte 570413

Aufzählungsliterale waren für Java 7 geplant, haben es aber nicht geschafft. Also noch nichts Automatisches.

Sie können die Guave verwenden Sets :

Sets.newHashSet("a", "b", "c")

Oder Sie können die folgende Syntax verwenden, die eine anonyme Klasse erstellt, aber das ist umständlich:

Set<String> h = new HashSet<String>() {{
    add("a");
    add("b");
}};

61 Stimmen

@DD es ist ein Hack, weil es eine anonyme innere Unterklasse von HashSet mit einem statischen Initialisierungsabschnitt erstellt, der die add()-Methode aufruft, was für diese Situation definitiv zu viel ist. Ich liebe es!

47 Stimmen

Die doppelte Klammerinitialisierung ist ein sehr gefährlicher Hack. Die anonyme Klasse hat eine implizite Verknüpfung mit der äußeren Klasse, was zu Speicherlecks führen kann. Wer die durch die doppelte Klammer initialisierte Menge besitzt, besitzt auch die Klasse, in der die Menge erstellt wurde.

7 Stimmen

@fhucho Die Methode ist sehr beliebt für die Einstellung von Mock-Objekt Erwartungen in (sagen wir) JMock, und es macht Sinn, in diesem Fall auch in Anbetracht der Speicher Leck Risiko (Tests sind kurzlebige Prozesse, deren Speicher-Footprint ist nicht wichtig).

338voto

akhil_mittal Punkte 20953

Wenn Sie nach der kompaktesten Art der Initialisierung eines Sets suchen, dann war das in Java9 :

Set<String> strSet = Set.of("Apple", "Ball", "Cat", "Dog");

\===================== Ausführliche Antwort unten ==========================

Java 10 verwenden (Unveränderbare Sets)

Set<String> strSet1 = Stream.of("A", "B", "C", "D")
         .collect(Collectors.toUnmodifiableSet());

Hier würde der Collector tatsächlich die in Java 9 eingeführte unveränderbare Menge zurückgeben, wie aus der Anweisung set -> (Set<T>)Set.of(set.toArray()) im Quellcode.

Ein Punkt ist zu beachten ist, dass die Methode Collections.unmodifiableSet() gibt eine unveränderbare Ansicht der angegebenen Menge zurück (wie in der Dokumentation angegeben). Eine unveränderbare Ansicht Sammlung ist eine unveränderbare Sammlung, die auch eine Sicht auf eine zurückliegende Sammlung ist. Beachten Sie, dass Änderungen an der zugrundeliegenden Sammlung puede noch möglich sein, und wenn sie auftreten, sind sie durch die unveränderliche Ansicht sichtbar. Aber die Methode [Collectors.toUnmodifiableSet()](https://docs.oracle.com/javase/10/docs/api/java/util/stream/Collectors.html#toUnmodifiableSet()) gibt zurück. wirklich unabänderlich sich einstellen Java 10 .


Java 9 verwenden (Unveränderbare Sets)

Im Folgenden werden die am kompaktesten Art und Weise, ein Set zu initialisieren:

Set<String> strSet6 = Set.of("Apple", "Ball", "Cat", "Dog");

Wir haben 12 überladene Versionen davon Lebensmittelfabrik Methode:

static <E> Set<E> of()

static <E> Set<E> of(E e1)

static <E> Set<E> of(E e1, E e2)

// ....und so weiter

static <E> Set<E> of(E... elems)

Dann stellt sich natürlich die Frage warum wir überladene Versionen brauchen, wenn wir var-args haben ? Die Antwort lautet: Jede var-arg-Methode erzeugt intern ein Array, und wenn man die überladenen Versionen hätte, würde man die unnötige Erzeugung von Objekten vermeiden und auch den Aufwand für die Garbage Collection vermeiden.


Verwendung von Java 8 (Modifizierbare Sets)

Verwendung von Stream in Java 8.

Set<String> strSet1 = Stream.of("A", "B", "C", "D")
         .collect(Collectors.toCollection(HashSet::new));

// stream from an array (String[] stringArray)
Set<String> strSet2 = Arrays.stream(stringArray)
         .collect(Collectors.toCollection(HashSet::new));

// stream from a list (List<String> stringList)
Set<String> strSet3 = stringList.stream()
         .collect(Collectors.toCollection(HashSet::new));

Java 8 verwenden (Unveränderbare Sets)

Verwendung von Collections.unmodifiableSet()

Wir können verwenden Collections.unmodifiableSet() als:

Set<String> strSet4 = Collections.unmodifiableSet(strSet1);

Aber es sieht etwas umständlich aus und wir können unseren eigenen Collector so schreiben:

class ImmutableCollector {
    public static <T> Collector<T, Set<T>, Set<T>> toImmutableSet() {
        return Collector.of(HashSet::new, Set::add, (l, r) -> {
            l.addAll(r);
            return l;
        }, Collections::unmodifiablSet);
    }
}

Und dann verwenden Sie es als:

Set<String> strSet4 = Stream.of("A", "B", "C", "D")
             .collect(ImmutableCollector.toImmutableSet());

Verwendung von Collectors.collectingAndThen()

Ein anderer Ansatz ist die Anwendung der Methode Collectors.collectingAndThen() mit dem wir zusätzliche Finishing-Transformationen durchführen können:

import static java.util.stream.Collectors.*;
Set<String> strSet5 = Stream.of("A", "B", "C", "D").collect(collectingAndThen(
   toCollection(HashSet::new),Collections::unmodifiableSet));

Wenn wir uns nur um Set dann können wir auch Collectors.toSet() anstelle von Collectors.toCollection(HashSet::new) .

Prüfen Sie auch diese Antwort für Java 8.

1 Stimmen

Danke für den Abschnitt "Warum brauchen wir überladene Versionen, wenn wir var-args haben?

1 Stimmen

Eine Warnung für die zukünftigen Leser für Set.of() . Wenn Sie versuchen, doppelte Elemente hinzuzufügen, wird ein IllegalArgumentException

224voto

In Java 8 würde ich verwenden:

Set<String> set = Stream.of("a", "b").collect(Collectors.toSet());

Dies gibt Ihnen eine veränderbare Set vorinitialisiert mit "a" und "b". Beachten Sie, dass dies in JDK 8 zwar ein HashSet In der Spezifikation wird dies nicht garantiert, und dies könnte sich in Zukunft ändern. Wenn Sie speziell eine HashSet tun Sie stattdessen dies:

Set<String> set = Stream.of("a", "b")
                        .collect(Collectors.toCollection(HashSet::new));

43 Stimmen

Dies ist sogar noch ausführlicher und unnötig kompliziert als der einfache alte Code in der ursprünglichen Frage.

14 Stimmen

@Natix Für 2 Elemente ist es ausführlicher, aber diese Darstellung wird prägnant, wenn Sie die Menge mit mehr Elementen (10-100) hart kodieren müssen.

7 Stimmen

@Natix Ja, aber es ist inline, in manchen Fällen ist das ein Vorteil

93voto

coobird Punkte 155882

Es gibt mehrere Möglichkeiten:

Initialisierung der doppelten Klammer

Bei dieser Technik wird eine anonyme innere Klasse erstellt, die einen Instanzinitialisierer hat, der String s zu sich selbst, wenn eine Instanz erstellt wird:

Set<String> s = new HashSet<String>() {{
    add("a");
    add("b");
}}

Beachten Sie, dass dadurch eine neue Unterklasse von HashSet jedes Mal, wenn sie verwendet wird, auch wenn man nicht explizit eine neue Unterklasse schreiben muss.

Eine nützliche Methode

Das Schreiben einer Methode, die eine Set die mit den gewünschten Elementen initialisiert wird, ist nicht allzu schwer zu schreiben:

public static Set<String> newHashSet(String... strings) {
    HashSet<String> set = new HashSet<String>();

    for (String s : strings) {
        set.add(s);
    }
    return set;
}

Der obige Code erlaubt nur die Verwendung eines String aber es sollte nicht allzu schwierig sein, die Verwendung eines beliebigen Typs mit Hilfe von Generika zu ermöglichen.

Eine Bibliothek benutzen

Viele Bibliotheken verfügen über eine praktische Methode zur Initialisierung von Sammlungsobjekten.

Zum Beispiel, Google-Sammlungen hat eine Sets.newHashSet(T...) Methode, die eine HashSet mit Elementen eines bestimmten Typs.

21 Stimmen

GoogleCollections hat auch ImmutableSet.of(T...) . In den meisten Fällen müssen Sie die Menge später nicht mehr ändern, und in diesem Fall hat die Verwendung einer unveränderlichen Menge viele Vorteile.

4 Stimmen

Zur Klärung wird bei jeder Verwendung eine neue Unterklasse von HashSet erstellt bedeutet "jedes Mal, wenn es verschlüsselt ". Jede Ausführung fait no eine neue Unterklasse erstellen.

0 Stimmen

Die Einleitung einer doppelten Klammer kann gefährlich sein, wenn Sie nicht wissen, was Sie tun; informieren Sie sich über die Auswirkungen, bevor Sie sie verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X