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?
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.
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");
}};
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));
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.
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 .
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.
si vous n'avez qu'une valeur initiale dans l'ensemble, cela sera suffisant:
Set<String> h = Collections.singleton("a");
je pense que le plus lisible est tout simplement d'utiliser google Guava:
Set<String> StringSet = Sets.newSet("a", "b", "c");
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 .
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");
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;
}
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, ... );
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.
import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");
ou
import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");
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));
}
(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");
}})
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.
avec la libération de java9 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");
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));
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);
}
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);
}
};
}
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());
}
}