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.
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.
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.
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));
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.
@Gennadiy Kann bestätigen, dass die Rautennotation gut funktioniert (sogar über die Set-Deklaration und HashSet-Zuweisung hinweg).
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");
}};
@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!
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.
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 ==========================
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 .
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 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));
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());
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.
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));
Dies ist sogar noch ausführlicher und unnötig kompliziert als der einfache alte Code in der ursprünglichen Frage.
@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.
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.
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.
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.
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.
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.