1. 概要

このクイックチュートリアルでは、リストを別のリストにコピーするさまざまな方法と、その過程で発生する一般的なエラーについて説明します。

コレクションの使用方法の概要については、こちらの記事を参照してください。

2. コンストラクタ

List をコピーする簡単な方法は、コレクションを引数として取るコンストラクターを使用することです。

List<Plant> copy = new ArrayList<>(list);

ここでは参照をコピーしており、オブジェクトのクローンを作成していないため、1つの要素で行われたすべての修正は、両方のリストに影響します。

そのため、不変オブジェクトをコピーするためにコンストラクターを使用することをお勧めします。

List<Integer> copy = new ArrayList<>(list);

Integerは不変のクラスです。 その値はインスタンスの作成時に設定され、変更することはできません。

したがって、 Integer 参照は複数のリストとスレッドで共有でき、誰もがその値を変更できる方法はありません。

3. リスト同時アクセス例外

リストでの一般的な問題はConcurrentAccessExceptionです。これは通常、リストをコピーしようとしているときに、おそらく別のスレッドでリストを変更していることを意味します。

この問題を修正するには、次のいずれかを行う必要があります。

  • 同時アクセス用に設計されたコレクションを使用する
  • コレクションを適切にロックして、繰り返し処理します
  • 元のコレクションをコピーする必要がないようにする方法を見つける

最後のアプローチを考えると、スレッドセーフではありません。 最初のオプションで問題を解決したい場合は、 CopyOnWriteArrayList を使用することをお勧めします。この場合、基になる配列の新しいコピーを作成することにより、すべての変更操作が実装されます。

詳細については、この記事を参照してください。

Collection をロックする場合は、ReentrantReadWriteLockなどのシリアル化された読み取り/書き込みアクセスにロックプリミティブを使用できます。

4. AddAll

要素をコピーする別のアプローチは、addAllメソッドを使用することです。

List<Integer> copy = new ArrayList<>();
copy.addAll(list);

このメソッドを使用するときは常に、コンストラクターと同様に、両方のリストのコンテンツが同じオブジェクトを参照することを覚えておくことが重要です。

5. Collections.copy

Collections クラスは、コレクションを操作する、またはコレクションを返す静的メソッドのみで構成されます。

それらの1つはcopyで、これには少なくともソースと同じ長さのソースリストと宛先リストが必要です。

元の要素など、コピー先リスト内のコピーされた各要素のインデックスを維持します。

List<Integer> source = Arrays.asList(1,2,3);
List<Integer> dest = Arrays.asList(4,5,6);
Collections.copy(dest, source);

上記の例では、 dest リストの以前のすべての要素が上書きされました。これは、両方のリストのサイズが同じであるためです。

宛先リストのサイズがソースよりも大きい場合:

List<Integer> source = Arrays.asList(1, 2, 3);
List<Integer> dest = Arrays.asList(5, 6, 7, 8, 9, 10);
Collections.copy(dest, source);

ここでは、最初の3つの項目だけが上書きされ、リストの残りの要素は保存されています。

6. Java8の使用

このバージョンのJavaは、新しいツールを追加することで可能性を広げます。 次の例で説明するのは、Streamです。

List<String> copy = list.stream()
  .collect(Collectors.toList());

このオプションの主な利点は、スキップとフィルターを使用できることです。 次の例では、最初の要素をスキップします。

List<String> copy = list.stream()
  .skip(1)
  .collect(Collectors.toList());

String、の長さでフィルタリングしたり、オブジェクトの属性を比較したりすることもできます。

List<String> copy = list.stream()
  .filter(s -> s.length() > 10)
  .collect(Collectors.toList());
List<Flower> flowers = list.stream()
  .filter(f -> f.getPetals() > 6)
  .collect(Collectors.toList());

nullセーフな方法で作業したい可能性があります。

List<Flower> flowers = Optional.ofNullable(list)
  .map(List::stream)
  .orElseGet(Stream::empty)
  .collect(Collectors.toList());

この方法でも要素をスキップしたい場合があります。

List<Flower> flowers = Optional.ofNullable(list)
  .map(List::stream).orElseGet(Stream::empty)
  .skip(1)
  .collect(Collectors.toList());

7. Java10の使用

最後に、最新のJavaバージョンの1つを使用すると、指定された Collection:の要素を含む不変のListを作成できます。

List<T> copy = List.copyOf(list);
唯一の条件は、指定されたコレクションがnullであってはならず、null要素が含まれていてはならないということです。

8. 結論

この記事では、リストを異なるJavaバージョンの別のリストにコピーするさまざまな方法を学びました。 また、プロセスで発生する一般的なエラーについても調べました。
いつものように、コードサンプルはGitHub、hereおよびhereにあります。