web-dev-qa-db-ja.com

構築によってHashSet値を初期化する方法?

初期値でSetを作成する必要があります。

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

これを1行のコードで実行する方法はありますか?たとえば、最後の静的フィールドに役立ちます。

632
Serg

私が使用している速記はそれほど時間的に効率的ではありませんが、単一行に収まります。

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

繰り返しますが、これは配列を作成し、リストに変換し、そのリストを使用してセットを作成しているため、時間効率が良くありません。

静的ファイナルセットを初期化するとき、私は通常このように書く:

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

スタティックな初期化では、やや見苦しく効率が悪くなることはありません。

820
Gennadiy

コレクションリテラルはJava 7用にスケジュールされていましたが、うまくいきませんでした。だから自動は何もしていません。

Guavaの Sets を使うことができます。

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

あるいは、次のような構文を使用して匿名クラスを作成することもできますが、それは厄介です。

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

Java 8では、私は使用します:

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

これにより、 "a"と "b"で事前に初期化された可変のSetが得られます。 JDK 8ではこれはHashSetを返しますが、仕様はそれを保証するものではなく、将来変更される可能性があります。特にHashSetが欲しい場合は、代わりにこれを行ってください。

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

Java 10(修正不可能なセット)の使用

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

ここでコレクターは実際にはソースコードのステートメントset -> (Set<T>)Set.of(set.toArray())から明らかなようにJava 9で導入された変更不可能なセットを返すでしょう。

Java 9(修正不可能なセット)の使用

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

この コンビニエンスファクトリ methodには12のオーバーロードバージョンがあります。

static <E> Set<E> of()

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

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

// ....等々

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

それでは自然な質問はなぜvar-argsの時にオーバーロードされたバージョンが必要なのでしょうか?答え:すべてのvar-argメソッドは内部的に配列を作成し、オーバーロードされたバージョンを持つことで不要なオブジェクトの作成を回避できガベージコレクションのオーバーヘッドから。

Java 8(修正可能セット)の使用

Java 8で Stream を使用する。

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

Java 8の使用(変更不可能なセット)

Collections.unmodifiableSetの使用 - Collections.unmodifiableSetを次のように使用できます。

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

しかし、それは少し厄介に見えます、そして私たちはこのように私たち自身のコレクターを書くことができます:

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

そしてそれを次のように使います。

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

Using Collectors.collectingAndThen - もう1つの方法は、追加の仕上げ変換を実行できるメソッドCollectors.collectingAndThenを使用することです。

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

Setだけを気にするのであれば、Collectors.toSet()の代わりにCollectors.toCollection(HashSet::new)を使うこともできます。


注意すべき点は、メソッドCollections::unmodifiableSetが、 doc のように、指定されたセットの変更不可能なビューを返すことです。変更不可能なビューコレクションは、変更不可能なコレクションであり、バッキングコレクションに対するビューでもあります。バッキングコレクションへの変更はまだ可能である可能性があり、変更が加えられても変更不可能なビューを通して表示されますが、メソッドCollectors.unmodifiableSetJava 10)で本当に不変のセットを返します。

117
i_am_zero

いくつかの方法があります。

二重括弧の初期化

これは、インスタンスが作成されたときにStringsを自分自身に追加するインスタンス初期化子を持つ無名の内部クラスを作成する手法です。

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

新しいサブクラスを明示的に記述する必要はありませんが、これが使用されるたびに実際に HashSet の新しいサブクラスが作成されることに注意してください。

ユーティリティメソッド

目的の要素で初期化された Set を返すメソッドを書くのは、それほど難しくありません。

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

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

上記のコードはStringの使用のみを許可していますが、総称を使用して任意の型の使用を許可することはそれほど難しくないはずです。

ライブラリを使う

多くのライブラリには、コレクションオブジェクトを初期化するための便利なメソッドがあります。

例えば、 Google Collections には Sets.newHashSet(T...) メソッドがあり、これはHashSetに特定の型の要素を追加します。

82
coobird

Setに初期値が1つしかない場合は、これで十分です。

Set<String> h = Collections.singleton("a");
32
Lu55

あなたはJava 6でそれをすることができます:

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

しかし、なぜ?要素を明示的に追加するよりも読みやすくなるとは思いません。

27
Jason Nichols

最も便利な方法の1つは、コレクションと可変引数をとるgeneric Collections.addAll() methodの使用です。

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

私が最も読みやすいのは単にグーグルグアバを使用することであると感じます:

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

Java 9では、次のことができます。

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

そして、要素を含む不変のSetが得られます。詳細は、Oracle インタフェースSetのドキュメント を参照してください。

21
Mathias Bader

新しいHashSetsを作成するための coobird's answer's utility関数の一般化:

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

含まれているSetの型が列挙型の場合は、Javaで構築されたファクトリメソッドがあります(1.5以降)。

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

Eclipseのコレクション を使って、1つのステートメントに文字 'a'と 'b'を含むSetを初期化する方法がいくつかあります。 Eclipse Collectionsにはオブジェクト型とプリミティブ型の両方のコンテナがあるので、両方の可変、不変、同期、および変更不可能なバージョンに加えてSet<String>または CharSet を使用する方法を説明しました。

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 CollectionsはJava 5 - 8と互換性があります。

注:私はEclipseコレクションのコミッターです。

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

または

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

副作用のない(醜い)ダブルブレースの初期化:

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

しかし、場合によっては、それが最終コレクションを変更できないようにするのに良い匂いであると述べたなら、それは本当に役に立ちます。

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

少し複雑ですが、Java 5から機能します。

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

読みやすくするためにヘルパーメソッドを使用します。

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

public Set<String> asSet(String... values) {
    return new HashSet<String>(Java.util.Arrays.asList(values));
}
4
Aaron Digulla

ちょっと注意してください、ここで述べたどの良いアプローチにもかかわらず、これが通常変更されないデフォルトである場合(作成しているライブラリのデフォルト設定のように)、このパターンに従うのは良い考えです。 :

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

その利点は、そのクラスに作成したインスタンスの数と、デフォルトがどの程度変更されるかによって異なります。

このパターンに従うことにした場合は、最も読みやすい集合初期化の方法を選ぶことになります。あなたが一度だけセットを初期化することになるので、異なる方法の間の効率の微妙な違いはおそらくあまり問題にならないでしょう。

3
Amr Mostafa

Java 8 を使ってHashSetを作成することができます。

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

そして変更不可能な集合が欲しいならば、私たちは以下のように効用メソッドを作成することができます

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

このメソッドは以下のように使用できます。

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

Java9 および コンビニエンスファクトリメソッド のリリースにより、これはよりクリーンな方法で可能になります。

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

初期化に静的ブロックを使用できます。

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
Ups

Michael Berdyshevによる回答とGenericsを組み合わせ、initialCapacityでコンストラクターを使用して、Arrays.asListバリアントと比較します。

  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
  }
  • これは、initにいくつかの値を渡す場合に役立ちます。他の方法で大規模に使用する場合
  • 誤ってタイプをbuildSetModifと混合すると、結果のTは? extends Objectになりますが、これはおそらく望んでいないものです。これはbuildSetModifTypeSafeバリアントでは起こり得ません。つまり、buildSetModifTypeSafe(1, 2, "a");はコンパイルされません
0

これはエレガントな解決策です。

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
ToxiCore

ここではBuilderパターンが役立ちます。今日も同じ問題がありました。 Setオブジェクトの参照を返すためにSetの変更操作が必要な場合建てられました。私が書いたビルダークラスは次のようになります(私の場合は外部クラスの静的な内部クラスですが、それ自身の独立したクラスにすることもできます)

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

SetがaddAll()add()の対応するものを返すSetであるSet.add()Set.addAll()メソッドに注目してください。最後に、ビルダーがカプセル化したSetへの参照を返すbuild()メソッドに注目してください。次に、この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
Jose Quijada