Comment initialiser les valeurs HashSet par construction?

je dois créer un Set avec des valeurs initiales.

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

y a-t-il un moyen de faire cela en une seule ligne de code?

540
demandé sur nullpointer 2010-01-11 15:31:50

22 réponses

Il y a un raccourci que j'utilise qui n'est pas très efficace, mais tient sur une seule ligne:

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

encore une fois, ce n'est pas efficace dans le temps puisque vous construisez un tableau, convertissez en une liste et utilisez cette liste pour créer un ensemble.

lors de l'initialisation des ensembles finaux statiques, Je l'écris habituellement comme ceci:

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

un peu moins laid et l'efficacité n'a pas d'importance pour l'initialisation statique.

711
répondu Gennadiy 2017-07-25 13:43:45

Collection littérales étaient prévues pour Java 7, mais ne l'ont pas fait dans. Donc rien d'automatique encore.

vous pouvez utiliser la goyave Sets :

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

ou vous pouvez utiliser la syntaxe suivante, qui créera une classe anonyme, mais c'est hacky:

Set<String> h = new HashSet<String>() {{
    add("a");
    add("b");
}};
300
répondu Bozho 2012-05-09 17:19:58

en Java 8 j'utiliserais:

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

cela vous donne un mutable Set pré-initialisé avec" a "et"b". Notez que bien que dans JDK 8 cela renvoie un HashSet , la spécification ne le garantit pas, et cela pourrait changer à l'avenir. Si vous voulez spécifiquement un HashSet , faites ceci à la place:

Set<String> set = Stream.of("a", "b")
                        .collect(Collectors.toCollection(HashSet::new));
153
répondu Christian Ullenboom 2015-05-16 16:40:31

il y a plusieurs façons:

Double croisillon d'initialisation

c'est une technique qui crée une classe interne anonyme qui a un initialiseur d'instance qui ajoute String à lui-même quand une instance est créée:

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

gardez à l'esprit que cela créera effectivement une nouvelle sous-classe de HashSet chaque fois qu'il est utilisé, même si on ne avoir à écrire explicitement une nouvelle sous-classe.

Une méthode utilitaire

écrire une méthode qui renvoie une Set qui est initialisée avec les éléments désirés n'est pas trop difficile à écrire:

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

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

le code ci-dessus ne permet l'utilisation que d'un String , mais il ne devrait pas être trop difficile d'autoriser l'utilisation de tout type utilisant des génériques.

Utiliser une bibliothèque

plusieurs bibliothèques ont une méthode pratique pour initialiser des objets de collections.

par exemple, Google Collections a un Sets.newHashSet(T...) méthode qui peuplera un HashSet avec des éléments d'un type spécifique.

79
répondu coobird 2014-01-13 04:59:19

Utilisant Java 10 (Unmodifiable Sets)

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

ici, le collecteur retournerait effectivement l'ensemble non modifiable introduit dans Java 9 tel qu'il ressort de la déclaration set -> (Set<T>)Set.of(set.toArray()) dans le code source.

Utilisant Java 9 (Unmodifiable Sets)

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

À L'Aide De Java 8 (Modifiable)

utilisant Stream en 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));

Utilisant Java 8 (Unmodifiable Sets)

À L'Aide De Collections.unmodifiableSet - nous pouvons utiliser Collections.unmodifiableSet comme:

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

, Mais il semble un peu maladroit et nous pouvons écrire notre propre collectionneur comme ceci:

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

et l'utiliser comme:

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

Utilisant Des Collecteurs.collecte et ensuite - une autre approche est d'utiliser la méthode Collectors.collectingAndThen qui nous permet d'effectuer des transformations de finition supplémentaires:

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

si nous nous soucions seulement de Set alors nous pouvons aussi utiliser Collectors.toSet() à la place de Collectors.toCollection(HashSet::new) .


un point à noter est que la méthode Collections::unmodifiableSet renvoie une vue non modifiable de l'ensemble spécifié, comme dans doc . Une collection de vues non modifiable est une collection il s'agit d'une vue imprenable sur une collection de supports. Notez que des changements à la collection de supports peuvent encore être possibles, et s'ils se produisent, ils sont visibles à travers la vue non modifiable. Mais la méthode Collectors.unmodifiableList retourne vraiment immuable défini dans Java 10 .

75
répondu i_am_zero 2018-10-12 06:14:10

vous pouvez le faire en Java 6:

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

mais pourquoi? Je ne le trouve pas plus lisible que d'ajouter explicitement des éléments.

26
répondu Jason Nichols 2010-01-11 12:36:23

si vous n'avez qu'une valeur initiale dans l'ensemble, cela sera suffisant:

Set<String> h = Collections.singleton("a");
26
répondu Lu55 2015-10-05 07:51:19

je pense que le plus lisible est tout simplement d'utiliser google Guava:

Set<String> StringSet = Sets.newSet("a", "b", "c");
23
répondu LanceP 2015-05-04 14:16:30

avec Java 9 Vous pouvez faire ce qui suit:

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

et vous obtiendrez un jeu immuable contenant les éléments. Pour plus de détails voir L'Oracle documentation de l'ensemble d'interface .

18
répondu Mathias Bader 2018-04-03 12:02:31

L'un des moyens les plus commodes est l'utilisation des Collections génériques .addAll () méthode, qui prend une collection et varargs:

Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");
17
répondu Michael Berdyshev 2017-02-10 19:59:37

Une généralisation de coobird la réponse est fonction d'utilité pour la création de nouveaux HashSet s:

public static <T> Set<T> newHashSet(T... objs) {
    Set<T> set = new HashSet<T>();
    for (T o : objs) {
        set.add(o);
    }
    return set;
}
14
répondu Mark Elliot 2017-05-23 11:55:00

si le type contenu de L'ensemble est une énumération, alors il y a la méthode java built factory (depuis 1.5):

Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
8
répondu Heri 2015-12-23 07:16:16

Avec Eclipse Collections il y a plusieurs façons d'initialiser un Set contenant les caractères 'a' et 'b' dans une déclaration. Eclipse Collections a des conteneurs pour les types d'objets et primitifs, donc j'ai illustré comment vous pourriez utiliser un Set<String> ou CharSet en plus de mutable, immuable, synchronisé et non modifiable versions des deux.

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

Collections Eclipse est compatible avec Java 5 - 8.

Remarque: je suis un committer pour Eclipse Collections.

5
répondu Donald Raab 2016-02-29 21:10:37
import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");

ou

import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");
5
répondu Bryan Correll 2017-07-14 16:29:12

un peu alambiqué mais fonctionne à partir de Java 5:

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

utilisez une méthode d'aide pour la rendre lisible:

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

public Set<String> asSet(String... values) {
    return new HashSet<String>(java.util.Arrays.asList(values));
}
4
répondu Aaron Digulla 2010-01-11 12:38:21

(laid) Double initialisation Brace sans effets secondaires:

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

mais dans certains cas, si nous avons mentionné que c'est une bonne odeur pour rendre les collections finales indiscutables, il pourrait être vraiment utile:

final Set<String> a = Collections.unmodifiableSet(new HashSet<String>(){{
    add("1");
    add("2");
}})
4
répondu egorlitvinenko 2017-08-09 19:31:07

Juste une petite remarque, indépendamment de l'amende approches mentionnées ici, vous vous retrouvez avec, si c'est un défaut qui va généralement non modifiée (comme un paramètre par défaut dans une bibliothèque de la création), c'est une bonne idée de suivre ce modèle:

// 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;

l'avantage dépend du nombre d'instances que vous créez de cette classe et de la probabilité que les valeurs par défaut seront changées.

Si vous décidez de suivre ce modèle, vous vous pouvez aussi choisir la méthode d'initialisation de set la plus lisible. Comme les différences micro dans l'efficacité entre les différentes méthodes ne seront probablement pas d'importance beaucoup que vous serez initialisant l'ensemble une seule fois.

3
répondu Amr Mostafa 2015-11-11 09:21:27

avec la libération de et le méthodes d'usine de commodité cela est possible d'une manière plus propre que:

Set set2 = Set.of("a", "b", "c");
3
répondu nullpointer 2017-09-27 17:55:50

utilisant Java 8 nous pouvons créer HashSet comme:

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

Et si nous voulons inmodifiable ensemble nous pouvons créer une méthode utilitaire comme :

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

Cette méthode peut être utilisée comme :

 Stream.of("A", "B", "C", "D").collect(toImmutableSet(HashSet::new));
2
répondu rakhi 2017-12-08 15:19:16

peut utiliser le bloc statique pour l'initialisation:

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);
}
1
répondu Ups 2018-06-20 19:28:37

c'est une solution élégante:

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);
            }
        };
}
0
répondu ToxiCore 2015-05-12 14:37:14

le modèle de constructeur pourrait être utile ici. Aujourd'hui, j'ai eu le même problème. là où J'avais besoin D'opérations de mutation de Set pour me rendre une référence de L'Objet Set, pour que je puisse le passer à super class constructor pour qu'ils puissent continuer à ajouter au même set en construisant à leur tour un nouveau StringSetBuilder à partir du Set que la classe enfant vient de construire. La classe de constructeur que j'ai écrite ressemble à ceci (dans mon cas c'est une classe intérieure statique d'une classe extérieure, mais il peut être sa propre classe indépendante comme Eh bien):

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

noter les méthodes addAll() et add() , qui sont des contreparties de retour de Set.add() et Set.addAll() . Remarquez enfin la méthode build() , qui renvoie une référence à l'ensemble que le constructeur encapsule. Ci-dessous illustre ensuite comment utiliser ce Set builder:

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());
    }
}
0
répondu Jose Quijada 2018-01-13 05:01:38