[Java] Wie initialisiert man HashSet-Werte durch Konstruktion?


Answers

Sammlungsliterale wurden für Java 7 geplant, haben es aber nicht geschafft. Es ist also noch nichts automatisch.

Sie können Guavas Sets :

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

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

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

Ich muss ein Set mit Anfangswerten erstellen.

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

Gibt es eine Möglichkeit, dies in einer Codezeile zu tun?




Wenn der enthaltene Typ des Sets eine Aufzählung ist, dann gibt es eine Java-Factory-Methode (seit 1.5):

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



Sie können es in Java 6 tun:

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

Aber warum? Ich finde es nicht lesbarer als das explizite Hinzufügen von Elementen.




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);
            }
        };
}



Es gibt ein paar Möglichkeiten:

Doppelstreben-Initialisierung

Dies ist eine Technik, die eine anonyme innere Klasse erstellt, die einen Instanz-Initialisierer hat, der String s hinzufügt, wenn eine Instanz erstellt wird:

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

HashSet jeder Verwendung eine neue Unterklasse von HashSet wird, obwohl keine neue Unterklasse explizit geschrieben werden muss.

Eine Dienstprogrammmethode

Das Schreiben einer Methode, die ein Set zurückgibt, das mit den gewünschten Elementen initialisiert wird, ist nicht 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 zu schwierig sein, einen beliebigen Typ mit Generika zu verwenden.

Verwenden Sie eine Bibliothek

Viele Bibliotheken verfügen über eine bequeme Methode zum Initialisieren von Auflistungsobjekten.

Google Collections verfügt Sets.newHashSet(T...) B. über die Methode Sets.newHashSet(T...) , mit der ein HashSet mit Elementen eines bestimmten Typs HashSet .




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

oder

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



Ein wenig verschachtelt, aber funktioniert von Java 5:

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

Verwenden Sie eine Hilfsmethode, um es lesbar zu machen:

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

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



Mit Java 9 können Sie Folgendes tun:

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

und Sie erhalten ein unveränderliches Set mit den Elementen. Details finden Sie in der Oracle- Dokumentation der Schnittstelle Set .




Das Builder-Muster könnte hier von Nutzen sein. Heute hatte ich das gleiche Problem. wo ich Set muting-Operationen brauchte, um mir einen Verweis des Set-Objekts zurückzugeben, damit ich sie an den Superklassenkonstruktor übergeben kann, damit sie auch weiterhin zum selben Set hinzufügen können, indem sie wiederum einen neuen StringSetBuilder aus dem Set der Kindklasse konstruieren gerade gebaut. Die Builder-Klasse, die ich geschrieben habe, sieht so aus (in meinem Fall ist es eine statische innere Klasse einer äußeren Klasse, aber es kann auch ihre 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 Set-Gegenstücke von Set.add() und Set.addAll() . Beachten Sie schließlich die build() -Methode, die einen Verweis auf die vom Builder eingekapselte Menge zurückgibt. Im Folgenden wird 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());
    }
}



Mit Java 8 können wir HashSet wie HashSet erstellen:

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

Und wenn wir nicht änderbare Menge wollen, können wir eine Hilfsmethode erstellen als:

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 wie folgt verwendet werden:

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



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

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