Frage

Ich muss a erstellen Set mit Anfangswerten.

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

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

War es hilfreich?

Lösung

Es gibt eine Abkürzung, die ich benutze, die nicht sehr zeitlich effizient ist, sondern auf eine einzelne Zeile passt:

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

Dies ist wiederum nicht zeitlich effizient, da Sie ein Array konstruieren, in eine Liste konvertieren und diese Liste verwenden, um einen Satz zu erstellen.

Bei der Initialisierung statischer Endsätze schreibe ich es normalerweise wie folgt:

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 Effizienz spielt keine Rolle für die statische Initialisierung.

Andere Tipps

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

Sie können Guavas verwenden Sets:

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

Oder Sie können die folgende Syntax verwenden, die eine anonyme Klasse erstellt, aber sie ist hacky:

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

In Java 8 würde ich verwenden:

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

Dies gibt Ihnen ein Veränderbar Set Vorinitialisiert mit "A" und "B". Beachten Sie, dass dies in JDK 8 a HashSet, Die Spezifikation garantiert sie nicht, und dies könnte sich in Zukunft ändern. Wenn Sie speziell a wollen HashSet, Tun Sie dies stattdessen:

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

Verwenden von Java 10 (nicht modifizierbare Sets)

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

Hier würde der Sammler tatsächlich den in Java 9 eingeführten unerbittlichen Satz zurückgeben, wie aus der Erklärung ersichtlich set -> (Set<T>)Set.of(set.toArray()) im Quellcode.

Ein Punkt zu beachten ist das die Methode Collections.unmodifiableSet() Gibt eine unerbittliche Ansicht des angegebenen Satzes zurück (gemäß Dokumentation). Ein Uner modifizierbare Ansicht Die Sammlung ist eine Sammlung, die nicht modifizierbar ist und auch eine Aussicht auf eine Backing -Sammlung ist. Beachten Sie, dass sich die Backing -Sammlung ändert könnte Seien Sie immer noch möglich, und wenn sie auftreten, sind sie durch die unveränderbare Sicht sichtbar. Aber die Methode Collectors.toUnmodifiableSet() kehrt zurück Wirklich unveränderlich eingestellt Java 10.


Verwenden von Java 9 (nicht modifizierbare Sets)

Das Folgende ist das am kompaktesten Art der Initialisierung eines Satzes:

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

Wir haben 12 überlastete Versionen davon Convenience Factory Methode:

static <E> Set<E> of()

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

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

// ....usw

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

Dann ist eine natürliche Frage Warum wir überlastete Versionen brauchen, wenn wir var-args haben? Die Antwort lautet: Jede Var-Arg-Methode erstellt intern ein Array, und wenn die überladenen Versionen eine unnötige Erstellung von Objekten vermeiden und uns auch vor dem Overhead der Müllsammlung retten.


Verwenden von Java 8 (modifizierbare Sets)

Verwendung Strom 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));

Verwenden von Java 8 (nicht modifizierbare Sets)

Verwenden von Sammlungen.unmodifiableset ()

Wir können benutzen Collections.unmodifiableSet() wie:

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

Aber es sieht etwas umständlich aus und wir können unseren eigenen Sammler wie diesen 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 benutze es dann als:

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


Verwenden von Sammlern.Collectingandthen ()

Ein anderer Ansatz ist die Verwendung der Methode Collectors.collectingAndThen() Dadurch können wir zusätzliche Veredelungstransformationen durchführen:

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 darum kümmern Set Dann können wir auch verwenden Collectors.toSet() anstelle von Collectors.toCollection(HashSet::new).

Es gibt ein paar Möglichkeiten:

Doppelklamminitialisierung

Dies ist eine Technik, die eine anonyme innere Klasse erstellt, die einen Instanzinitialisierer hat, der hinzugefügt wird Strings für sich selbst, wenn eine Instanz erstellt wird:

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

Denken Sie daran, dass dies tatsächlich eine neue Unterklasse von erzeugen wird HashSet Jedes Mal, wenn es verwendet wird, muss man nicht explizit eine neue Unterklasse schreiben.

Eine Versorgungsmethode

Schreiben einer Methode, die a zurückgibt Set Was mit den gewünschten Elementen initialisiert wird, ist nicht zu 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 ermöglicht nur eine Verwendung von a String, aber es sollte nicht zu schwierig sein, die Verwendung eines Typs mit Generika zu ermöglichen.

Verwenden Sie eine Bibliothek

Viele Bibliotheken haben eine Komfortmethode, um Sammlungsobjekte zu initialisieren.

Zum Beispiel, Google -Kollektionen hat ein Sets.newHashSet(T...) Methode, die a bevölkert wird HashSet mit Elementen eines bestimmten Typs.

Wenn Sie nur einen Wert haben und einen bekommen möchten unveränderlich Setzen Sie dies würde ausreichen:

Set<String> immutableSet = Collections.singleton("a");

Eine der bequemsten Möglichkeiten ist die Verwendung von Generika Sammlung.Addall () Methode, die eine Sammlung und Varargs nimmt:

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

Sie können es in Java 6 machen:

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

Aber wieso? Ich finde es nicht lesbarer, als explizit Elemente hinzuzufügen.

Ich fühle mich am lesbarsten, um einfach Google Guava zu verwenden:

Set<String> StringSet = Sets.newSet("a", "b", "c");

Mit Java 9 können Sie Folgendes machen:

Set.of("a", "b");

Und Sie erhalten ein unveränderliches Set, das die Elemente enthält. Details finden Sie im Orakel Dokumentation des Schnittstellensatzes.

Eine Verallgemeinerung von Coobirds Antwort der Antworten Nützlichkeitsfunktion zum Erstellen neuer Erstellung HashSets:

public static <T> Set<T> newHashSet(T... objs) {
    Set<T> set = new HashSet<T>();
    for (T o : objs) {
        set.add(o);
    }
    return set;
}

Wenn der enthaltende Typ des Satzes eine Aufzählung ist, gibt es eine Java -erstellte Fabrikmethode (seit 1.5):

Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );

Mit Eclipse -Sammlungen Es gibt verschiedene Möglichkeiten, a zu initialisieren Set enthalten die Charaktere 'a' und 'B' in einer Aussage. Eclipse -Sammlungen haben Container sowohl für Objekt- als auch für primitive Typen. Daher habe ich veranschaulicht, wie Sie a verwenden können Set<String> oder CharSet Zusätzlich zu veränderlichen, unveränderlichen, synchronisierten und unveränderbaren Versionen von beiden.

Set<String> set =
    Sets.mutable.with("a", "b");
HashSet<String> hashSet =
    Sets.mutable.with("a", "b").asLazy().into(new HashSet<String>());
Set<String> synchronizedSet =
    Sets.mutable.with("a", "b").asSynchronized();
Set<String> unmodifiableSet =
    Sets.mutable.with("a", "b").asUnmodifiable();

MutableSet<String> mutableSet =
    Sets.mutable.with("a", "b");
MutableSet<String> synchronizedMutableSet =
    Sets.mutable.with("a", "b").asSynchronized();
MutableSet<String> unmodifiableMutableSet =
    Sets.mutable.with("a", "b").asUnmodifiable();

ImmutableSet<String> immutableSet =
    Sets.immutable.with("a", "b");
ImmutableSet<String> immutableSet2 =
    Sets.mutable.with("a", "b").toImmutable();

CharSet charSet =
    CharSets.mutable.with('a', 'b');
CharSet synchronizedCharSet =
    CharSets.mutable.with('a', 'b').asSynchronized();
CharSet unmodifiableCharSet =
    CharSets.mutable.with('a', 'b').asUnmodifiable();
MutableCharSet mutableCharSet =
    CharSets.mutable.with('a', 'b');
ImmutableCharSet immutableCharSet =
    CharSets.immutable.with('a', 'b');
ImmutableCharSet immutableCharSet2 =
    CharSets.mutable.with('a', 'b').toImmutable();

Eclipse -Sammlungen sind mit Java 5 - 8 kompatibel.

HINWEIS: Ich bin ein Kommitter für Sonnenfinsterniskollektionen.

import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");

oder

import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");

(hässliche) Initialisierung der Doppelklammer ohne Nebenwirkungen:

Set<String> a = new HashSet<>(new HashSet<String>() {{
    add("1");
    add("2");
}})

Wenn wir jedoch erwähnt haben, dass dies ein guter Geruch ist, um endgültige Sammlungen überfugbar zu machen, könnte dies wirklich nützlich sein:

final Set<String> a = Collections.unmodifiableSet(new HashSet<String>(){{
    add("1");
    add("2");
}})

Ein bisschen verworren, aber funktioniert von Java 5:

Set<String> h = new HashSet<String>(Arrays.asList(new String[] {  
    "a", "b"
}))

Verwenden Sie eine Helfermethode, um sie lesbar zu machen:

Set<String> h = asSet ("a", "b");

public Set<String> asSet(String... values) {
    return new HashSet<String>(java.util.Arrays.asList(values));
}

Nur eine kleine Notiz, unabhängig davon, welche der feinen Ansätze, mit denen Sie hier erwähnt haben :

// Initialize default values with the method you prefer, even in a static block
// It's a good idea to make sure these defaults aren't modifiable
private final static Set<String> DEFAULT_VALUES = Collections.unmodifiableSet(...);
private Set<String> values = DEFAULT_VALUES;

Der Nutzen hängt von der Anzahl der Fälle ab, die Sie dieser Klasse erstellen und wie wahrscheinlich es ist, dass Standardeinstellungen geändert werden.

Wenn Sie sich für dieses Muster entscheiden, können Sie auch die Methode der festgelegten Initialisierung auswählen, die am lesbarsten ist. Da die Mikrounterschiede in der Effizienz zwischen den verschiedenen Methoden wahrscheinlich nicht viel spielen werden, werden Sie den Satz nur einmal initialisieren.

Verwendung Java 8 Wir können erstellen HashSet wie:

Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));

Und wenn wir einen modifizierbaren Satz wünschen, können wir eine Versorgungsmethode erstellen wie:

public static <T, A extends Set<T>> Collector<T, A, Set<T>> toImmutableSet(Supplier<A> supplier) {
        return Collector.of(
                supplier,
                Set::add, (left, right) -> {
                    left.addAll(right);
                    return left;
                }, Collections::unmodifiableSet);
    }

Diese Methode kann verwendet werden als:

 Stream.of("A", "B", "C", "D").collect(toImmutableSet(HashSet::new));

Mit der Veröffentlichung von und die Convenience -Fabrikmethoden Dies ist auf sauberere Weise möglich:

Set set = Set.of("a", "b", "c");

Kann statischen Block für die Initialisierung verwenden:

private static Set<Integer> codes1=
        new HashSet<Integer>(Arrays.asList(1, 2, 3, 4));

private static Set<Integer> codes2 =
        new HashSet<Integer>(Arrays.asList(5, 6, 7, 8));

private static Set<Integer> h = new HashSet<Integer>();

static{
    h.add(codes1);
    h.add(codes2);
}

Dies ist eine elegante Lösung:

public static final <T> Set<T> makeSet(@SuppressWarnings("unchecked") T... o) {
        return new HashSet<T>() {
            private static final long serialVersionUID = -3634958843858172518L;
            {
                for (T x : o)
                   add(x);
            }
        };
}

Das Builder -Muster könnte hier von Nutzen sein. Heute hatte ich das gleiche Problem. Wo ich Set -Mutationsvorgänge brauchte, um mir eine Referenz des festgelegten Objekts zurückzugeben gerade gebaut. Die Builder -Klasse, die ich schrieb, sieht so aus (in meinem Fall ist es eine statische innere Klasse einer äußeren Klasse, aber es kann auch eine eigene unabhängige Klasse sein):

public interface Builder<T> {
    T build();
}

static class StringSetBuilder implements Builder<Set<String>> {
    private final Set<String> set = new HashSet<>();

    StringSetBuilder add(String pStr) {
        set.add(pStr);
        return this;
    }

    StringSetBuilder addAll(Set<String> pSet) {
        set.addAll(pSet);
        return this;
    }

    @Override
    public Set<String> build() {
        return set;
    }
}

Beachten Sie die addAll() und add() Methoden, die zurückgekehrte Kollegen von Set.add() und Set.addAll(). Beachten Sie endlich die build() Methode, die einen Verweis auf den Satz zurückgibt, den der Bauherr kapselt. Im Folgenden wird dann veranschaulicht, wie Sie diesen Set -Builder verwenden:

class SomeChildClass extends ParentClass {
    public SomeChildClass(String pStr) {
        super(new StringSetBuilder().add(pStr).build());
    }
}

class ParentClass {
    public ParentClass(Set<String> pSet) {
        super(new StringSetBuilder().addAll(pSet).add("my own str").build());
    }
}

Antwort von Antwort von Michael Berdyshev mit Generika und Verwendung des Konstruktors mit InitialCapacity, verglichen mit mit Arrays.asList Variante:

  import java.util.Collections;
  import java.util.HashSet;
  import java.util.Set;

  @SafeVarargs
  public static <T> Set<T> buildSetModif(final T... values) {
    final Set<T> modifiableSet = new HashSet<T>(values.length);
    Collections.addAll(modifiableSet, values);
    return modifiableSet;
  }

  @SafeVarargs
  public static <T> Set<T> buildSetModifTypeSafe(final T... values) {
    return new HashSet<T>(Arrays.asList(values));
  }

  @SafeVarargs
  public static <T> Set<T> buildeSetUnmodif(final T... values) {
    return Collections.unmodifiableSet(buildSetModifTypeSafe(values));
    // Or use Set.of("a", "b", "c") if you use Java 9
  }
  • Dies ist gut, wenn Sie einige Werte für Init verabschieden, für alles, was andere Methoden verwenden, verwenden Sie andere Methoden
  • Wenn Sie versehentlich Typen mit mischen buildSetModif Das resultierende T wird sein ? extends Object, was wahrscheinlich nicht das ist, was Sie wollen, das kann nicht mit dem passieren buildSetModifTypeSafe Variante, bedeutet das buildSetModifTypeSafe(1, 2, "a"); wird nicht kompilieren
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top