構造によってハッシュセット値を初期化する方法は?
-
19-09-2019 - |
質問
aを作成する必要があります Set
初期値で。
Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
コードの1行でこれを行う方法はありますか?たとえば、最終的な静的フィールドに役立ちます。
解決
私が使用する速記がありますが、それはあまり時間効率ではありませんが、単一の行に適合します。
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));
わずかに醜く、効率性は静的な初期化については関係ありません。
他のヒント
コレクションリテラルはJava 7に予定されていましたが、入っていませんでした。まだ自動的なものはありません。
Guavaを使用できます Sets
:
Sets.newHashSet("a", "b", "c")
または、次の構文を使用することもできます。これにより、匿名クラスが作成されますが、ハッキーです。
Set<String> h = new HashSet<String>() {{
add("a");
add("b");
}};
Java 8で使用します:
Set<String> set = Stream.of("a", "b").collect(Collectors.toSet());
これにより、可変が得られます Set
「A」と「B」で事前に開始されました。 JDK 8では、これは HashSet
, 、仕様はそれを保証するものではなく、これは将来変化する可能性があります。具体的にaが必要な場合 HashSet
, 、代わりにこれを行います:
Set<String> set = Stream.of("a", "b")
.collect(Collectors.toCollection(HashSet::new));
Java 10を使用する(変更できないセット)
Set<String> strSet1 = Stream.of("A", "B", "C", "D")
.collect(Collectors.toUnmodifiableSet());
ここで、コレクターは、声明から明らかなように、Java 9で導入された変更不可能なセットを実際に返します set -> (Set<T>)Set.of(set.toArray())
ソースコードで。
注意すべき点 それは方法です Collections.unmodifiableSet()
指定されたセットの変更不可能なビュー(ドキュメントに従って)を返します。 an 変更できないビュー コレクションは、変更できないコレクションであり、バッキングコレクションのビューでもあります。バッキングコレクションの変更に注意してください そうかもしれない まだ可能であり、それらが発生した場合、それらは変更できないビューを通して見える。しかし、方法 Collectors.toUnmodifiableSet()
戻り値 本当に不変 始まる Java 10.
Java 9の使用(変更できないセット)
以下は次のとおりです 最もコンパクト セットを初期化する方法:
Set<String> strSet6 = Set.of("Apple", "Ball", "Cat", "Dog");
これの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で。
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());
collectors.collectingandthen()を使用する
別のアプローチは、メソッドを使用することです 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)
.
いくつかの方法があります:
ダブルブレースの初期化
これは、追加するインスタンスイニシャルイザーを備えた匿名の内部クラスを作成する手法です String
インスタンスが作成されたときにそれ自体にs:
Set<String> s = new HashSet<String>() {{
add("a");
add("b");
}}
これは実際に新しいサブクラスを作成することに留意してください HashSet
新しいサブクラスを明示的に記述する必要はありませんが、使用するたびに使用されます。
ユーティリティ方法
aを返すメソッドを作成します 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コレクション があります Sets.newHashSet(T...)
a HashSet
特定のタイプの要素を使用。
値が1つだけで、取得したい場合 不変 これで十分です:
Set<String> immutableSet = Collections.singleton("a");
最も便利な方法の1つは、ジェネリックの使用です collections.addall() メソッド、コレクションとvarargsを取得します:
Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");
Java 6でそれを行うことができます:
Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));
しかし、なぜ?明示的に要素を追加するよりも読みやすいとは思いません。
最も読みやすいのは、Google Guavaを単に使用することだと感じています。
Set<String> StringSet = Sets.newSet("a", "b", "c");
Java 9を使用すると、次のことができます。
Set.of("a", "b");
そして、要素を含む不変のセットを取得します。詳細については、The Oracleを参照してください インターフェイスセットのドキュメント.
の一般化 Coobirdの答え 新規を作成するためのユーティリティ機能 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;
}
セットのタイプが含まれている場合、Javaビルドファクトリーメソッド(1.5以降)があります。
Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
と Eclipseコレクション 初期化する方法はいくつかあります Set
1つのステートメントにキャラクターの「A」と「B」を含む。 Eclipseコレクションには、オブジェクトタイプとプリミティブタイプの両方のコンテナがあるため、使用方法を説明しました。 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コレクションは、Java 5-8と互換性があります。
注:私はEclipseコレクションのコミッターです。
import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");
また
import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");
(醜い)副作用なしのダブルブレース初期化:
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");
}})
少し複雑ですが、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));
}
ここで言及されている素晴らしいアプローチのどれに関係なく、これが通常変更されていないデフォルトである場合(作成しているライブラリのデフォルト設定のように)、このパターンに従うことをお勧めします。 :
// 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;
利点は、そのクラスの作成されたインスタンスの数と、デフォルトが変更される可能性がどれほど可能かによって異なります。
このパターンに従うことにした場合、最も読みやすい設定の初期化の方法を選択することもできます。さまざまな方法間の効率のミクロの違いは、おそらくセットを一度だけ初期化するので、それほど重要ではないでしょう。
使用 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));
初期化には静的ブロックを使用できます。
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);
}
これはエレガントなソリューションです:
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);
}
};
}
ここでは、ビルダーパターンが使用される場合があります。今日、私は同じ問題を抱えていました。セットオブジェクトの参照を返すためにセットの変異操作が必要な場合、スーパークラスコンストラクターに渡すことができます。ちょうど建てられました。私が書いたビルダーのクラスはこのように見えます(私の場合、それは外側のクラスの静的な内部クラスですが、それは独自の独立したクラスでもあります):
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;
}
}
に注意してください addAll()
と add()
メソッド Set.add()
と Set.addAll()
. 。最後に注意してください build()
メソッドは、ビルダーがカプセル化するセットへの参照を返します。以下は、このセットビルダーの使用方法を示しています。
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());
}
}
応答を組み合わせます マイケル・ベルディーシェフ ジェネリックと、初期容量でコンストラクターを使用して、と比較して 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");
コンパイルされません