私はWebサービスから移入されたList<SomeBean>
を持っています。そのリストの内容を同じタイプの空のリストにコピー/複製したいです。リストをコピーするためのグーグル検索は私にCollections.copy()
メソッドを使うことを勧めました。私が見たすべての例では、コピー先のリストには、コピーを実行するための正確な数の項目が含まれているはずです。
私が使用しているリストはWebサービスを介して生成され、それは何百ものオブジェクトを含んでいるので、私は上記のテクニックを使用することはできません。それとも間違って使っていますか?とにかく、それを機能させるために、私はこのようなことをやろうとしました、しかし、私はまだIndexOutOfBoundsException
を得ました。
List<SomeBean> wsList = app.allInOne(template);
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());
wsListCopy=wsList.subList(0, wsList.size())
を使用しようとしましたが、コードの後半でConcurrentAccessException
を取得しました。ヒットして試用します。 :)
とにかく、私の質問は簡単です私のリストの全内容を別のリストにコピーするにはどうすればいいですか?もちろん、繰り返しではありません。
これを使うだけです:
List<SomeBean> newList = new ArrayList<SomeBean>(otherList);
注:それでも、スレッドセーフではありません。otherList
を別のスレッドから変更した場合は、そのotherList
(さらにnewList
)を CopyOnWriteArrayList
にするか、または次のようなロックプリミティブを使用します。 ReentrantReadWriteLock 同時にアクセスされるリストへの読み取り/書き込みアクセスをシリアル化します。
これは本当にいいJava 8の方法です:
List<String> list2 = list1.stream().collect(Collectors.toList());
もちろん、ここでの利点は、リストの一部のみをフィルタリングしてスキップできることです。
例えば.
//don't copy the first element
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
originalArrayList.addAll(copyArrayofList);
コピーにaddAll()メソッドを使用する場合は常に注意してください。同じオブジェクトへの両方の配列リスト(originalArrayListとcopyArrayofList)の参照の内容がリストに追加されるため、いずれかを変更した場合そのうちcopyArrayofListも同じ変更を反映します。
副作用が必要ない場合は、forループまたはwhileループを使用して、originalArrayListからcopyArrayofListに各要素をコピーする必要があります。
私はこのようなことをやろうとしました、しかし私はまだIndexOutOfBoundsExceptionを得ました。
ConcurrentAccessExceptionが発生しました
これは、リストをコピーしようとしている間に、おそらく別のスレッドでリストを変更していることを意味します。これを直すにはどちらかの方法があります
同時アクセス用に設計されたコレクションを使用してください。
コレクションを適切にロックして、それを繰り返すことができるようにします(または、これを実行するメソッドを呼び出すことができるようにします)。
元のリストをコピーする必要がないようにするための方法を見つけます。
Java 10以降:
List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);
List.copyOf()
は、与えられたList
の要素を含む変更不可能なCollection
を返します。
与えられたCollection
はnull
であってはならず、またnull
要素を含んではいけません。
また、List
のディープコピーを作成したい場合は、たくさんの良い答えを見つけることができます ここ 。
Java 8にはもう1つ、null-safeな方法があります。
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(List::stream)
.orElseGet(Stream::empty)
.collect(Collectors.toList());
1要素スキップしたい場合.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(List::stream)
.orElseGet(Stream::empty)
.skip(1)
.collect(Collectors.toList());
私は同じ問題を抱えていましたConcurrentAccessExceptionそしてmysolutionは次のようになりました:
List<SomeBean> tempList = new ArrayList<>();
for (CartItem item : prodList) {
tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);
そのため、一度に1つの操作しか動作せず、実行は回避されます。
私は似たようなことを試してみて、問題を再現することができました(IndexOutOfBoundsException)。以下が私の調査結果です。
1)Collections.copy(destList、sourceList)の実装は、最初にsize()メソッドを呼び出して宛先リストのサイズをチェックします。 size()メソッドの呼び出しは常にリスト内の要素数(この場合は0)を返すので、コンストラクタArrayList(capacity)は補助配列の初期容量のみを保証します。リストのサイズしたがって、常にIndexOutOfBoundsExceptionが発生します。
2)比較的簡単な方法は、コレクションを引数とするコンストラクタを使用することです。
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);
あなたはaddAll()を使うことができます。
例:wsListCopy.addAll(wsList);
indexOutOfBoundsException
に関しては、サブリストのargsが問題です。サブリストはサイズ1で終了する必要があります。ゼロベースであるため、リストの最後の要素は常にsize-1です。サイズ位置に要素がないため、エラーになります。
正解は見当たりません。ディープコピーが必要な場合は、オブジェクトを手動で繰り返しコピーする必要があります(コピーコンストラクタを使用できます)。