web-dev-qa-db-ja.com

コピーセットJava

TreeSetをコピーする方法はありますか?つまり、行くことは可能ですか

Set <Item> itemList;
Set <Item> tempList;

tempList = itemList;

または、セットを物理的に反復して、1つずつコピーする必要がありますか?

77
SNpn

これを行う別の方法は、 copy constructor を使用することです。

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>(oldSet);

または、空のセットを作成して要素を追加します。

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>();
newSet.addAll(oldSet);

cloneとは異なり、これらを使用すると、異なるセットクラス、異なるコンパレーターを使用したり、他の(非セット)コレクションタイプから移入することさえできます。


Setをコピーした結果は、元のSetの場合は要素であるオブジェクトへの参照を含む新しいSetであることに注意してください。要素オブジェクト自体はコピーまたは複製されません。これは、Java Collection AP​​Iが機能するように設計されている方法に準拠しています。これらのAPIは要素オブジェクトをコピーしません。

145
Stephen C

Java 8では、streamおよびcollectを使用してアイテムをコピーできます。

Set<Item> newSet = oldSet.stream().collect(Collectors.toSet());

または、ImmutableSetに収集できます(セットが変更されるべきでないことがわかっている場合)。

Set<Item> newSet = oldSet.stream().collect(ImmutableSet.toImmutableSet());
6
Yosi Dahari

@Stephen Cによって指定されたコピーコンストラクターは、作成したSetがある場合(または、どこから来たのかがわかっている場合)に移動する方法です。 Map.entrySet() に由来する場合、使用しているMap実装に依存します。

findbugs は言う

EntrySet()メソッドは、基礎となるMapのビューを返すことができます。このビューでは、反復中に単一のEntryオブジェクトが再利用され、返されます。 Java 1.6では、IdentityHashMapとEnumMapの両方がそうしました。そのようなマップを反復処理する場合、次の反復に進むまでエントリ値は有効です。たとえば、このようなentrySetをaddAllメソッドに渡そうとすると、事態はひどく悪くなります。

addAll()はコピーコンストラクターによって呼び出されるので、最後の1つのエントリのみのセットを見つけることができます。

ただし、すべてのMap実装がこれを行うわけではないため、実装がその点で安全であることがわかっている場合は、コピーコンストラクターを使用するのが確実です。それ以外の場合は、新しいEntryオブジェクトを自分で作成する必要があります。

Set<K,V> copy = new HashSet<K,V>(map.size());
for (Entry<K,V> e : map.entrySet())
    copy.add(new Java.util.AbstractMap.SimpleEntry<K,V>(e));

編集:Java 7およびJava 6u45(Stephen Cに感謝)で実行したテストとは異なり、findbugsコメントは適切ではないようです。 Java 6の以前のバージョン(u45より前)でもそうだったかもしれませんが、テストする必要はありません。

3
Matthieu

Java 10から開始:

Set<E> oldSet = Set.of();
Set<E> newSet = Set.copyOf(oldSet);

Set.copyOf() は、指定されたSetの要素を含む変更不可能なCollectionを返します。

指定されたCollectionnullであってはならず、null要素を含んではいけません。

3