1. 概要

Javaでは、リストのコピーを作成すると、 IndexOutOfBoundsException:「ソースがdestに適合しません」が生成される場合があります。この短いチュートリアルでは、 Collections.copy メソッドを使用するとこのエラーが発生する理由と、その解決方法。 リストのコピーを作成するために、Collections.copyの代替案も検討します。

2. 問題の再現

Collections.copy メソッドを使用して、リストのコピーを作成するメソッドから始めましょう。

static List<Integer> copyList(List<Integer> source) {
    List<Integer> destination = new ArrayList<>(source.size());
    Collections.copy(destination, source);
    return destination;
}

ここで、 copyList メソッドは、ソースリストのサイズに等しい初期容量を持つ新しいリストを作成します。 次に、ソースリストの要素を宛先リストにコピーしようとします。

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

ただし、 copyList メソッドを呼び出すと、例外 java.lang.IndexOutOfBoundsException:Sourceがdestに適合しません。

3. 例外の原因

何が悪かったのかを理解してみましょう。 Collections.copy メソッドのドキュメントによると:

宛先リストは、少なくともソースリストと同じ長さである必要があります。 それより長い場合、宛先リストの残りの要素は影響を受けません。

この例では、ソースリストのサイズに等しい初期容量を持つコンストラクターを使用して、新しいListを作成しました。 十分なメモリを割り当てるだけで、実際には要素を定義しません。容量とサイズはリストの異なる属性であるため、新しいリストのサイズはゼロのままです。

したがって、 Collections.copy メソッドがソースリストを宛先リストにコピーしようとすると、java.lang.IndexOutOfBoundsException。がスローされます。

4. ソリューション

4.1. Collections.copy

Collections.copy メソッドを使用して、リストを別のリストにコピーする実際の例を見てみましょう。

List<Integer> destination = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> source = Arrays.asList(11, 22, 33);
Collections.copy(destination, source);

この場合、ソースリストの3つの要素すべてを宛先リストにコピーしています。 Arrays.asList メソッドは、サイズだけでなく要素を使用してリストを初期化するため、ソースリストを宛先リストに正常にコピーできます。

Collections.copy メソッドの引数を入れ替えるだけでは、ソースリストのサイズがデスティネーションリストのサイズよりも小さいため、java.lang.IndexOutOfBoundsExceptionがスローされます[ X211X]。

このコピー操作の後、宛先リストは次のようになります。

[11, 22, 33, 4, 5]

Collections.copy メソッドに加えて、JavaにはListのコピーを作成する他の方法があります。 それらのいくつかを見てみましょう。

4.2. ArrayListコンストラクタ

リストをコピーする最も簡単な方法は、コレクションパラメーターを受け取るコンストラクターを使用することです。

List<Integer> source = Arrays.asList(11, 22, 33);
List<Integer> destination = new ArrayList<>(source);

ここでは、ソースリストを宛先リストのコンストラクターに渡すだけです。これにより、ソースリストの浅いコピーが作成されます。

宛先リストは、ソースリストによって参照される同じオブジェクトへの単なる別の参照になります。 したがって、参照によって行われたすべての変更は、同じオブジェクトに影響します。

したがって、コンストラクターを使用することは、整数文字列などの不変オブジェクトをコピーするための優れたオプションです。

4.3. addAll

もう1つの簡単な方法は、ListaddAllメソッドを使用することです。

List<Integer> destination = new ArrayList<>();
destination.addAll(source);

addAll メソッドは、ソースリストのすべての要素を宛先リストにコピーします。

このアプローチに関して注意すべき点がいくつかあります。

  1. ソースリストの浅いコピーを作成します。
  2. ソースリストの要素が宛先リストに追加されます。

4.4. Java8ストリーム

Java8はStreamAPI を導入しました。これは、Javaコレクションを操作するための優れたツールです。

stream()メソッドを使用して、Stream API を使用してリストのコピーを作成します。

List<Integer> copy = source.stream()
  .collect(Collectors.toList());

4.5. Java 10

リストのコピーは、Java10ではさらに簡単です。 copyOf()メソッドを使用すると、指定されたCollectionの要素を含む不変のリストを作成できます。

List<Integer> destination = List.copyOf(sourceList);

このアプローチを使用する場合は、入力リスト null でないこと、およびnull要素が含まれていないことを確認する必要があります。

5. 結論

この記事では、Collections.copyメソッドがIndexOutOfBoundException「ソースがdestにファイルされません」をスローする方法と理由を確認しました。 それに加えて、リストを別のリストにコピーするさまざまな方法も検討しました。

以前のJava-10の例Java10の例の両方がGitHubにあります。