36

次のようなリストがあるとします。

List<String> list = new ArrayList<>();
list.add("a");
list.add("h");
list.add("f");
list.add("s");

このリストを繰り返しながら、リストの最後に要素を追加したいと思います。しかし、リストの初期サイズまで繰り返したい、新しく追加された要素を繰り返し処理したくありません。

for (String s : list)
     /* Here I want to add new element if needed while iterating */

どうすればこれを行うことができますか?

4

6 に答える 6

50

そのために foreach ステートメントを使用することはできません。foreach は内部的にイテレータを使用しています:

このクラスの iterator および listIterator メソッドによって返される反復子はフェイルファストです。反復子の作成後にリストが構造的に変更された場合、反復子自体の remove または add メソッド以外の方法で、反復子は ConcurrentModificationException をスローします。

(ArrayList javadoc より)

foreach ステートメントでは、イテレータの add メソッドにアクセスできません。いずれにせよ、最後に追加されないため、必要な追加のタイプではありません。リストを手動でトラバースする必要があります。

int listSize = list.size();
for(int i = 0; i < listSize; ++i)
  list.add("whatever");

これは、ランダム アクセスを許可するリストに対してのみ有効であることに注意してください。リストが RandomAccess マーカー インターフェイスを実装しているかどうかを確認することで、この機能を確認できます。ArrayList にはランダム アクセスがあります。リンクされたリストはそうではありません。

于 2012-06-24T12:21:20.387 に答える
9

リストのコピーを反復処理し、元のリストに新しい要素を追加します。

for (String s : new ArrayList<String>(list))     
{
    list.add("u");
}

List 型の ArrayList オブジェクトのコピーを作成する方法を参照 してください。

于 2012-06-24T12:17:16.357 に答える
8

明示的なインデックス処理が必要なため、昔ながらの方法を繰り返すだけです。

List myList = ...
...
int length = myList.size();
for(int i = 0; i < length; i++) {
   String s = myList.get(i);
   // add items here, if you want to
}
于 2012-06-24T12:18:41.653 に答える
3

元のリストのコピー (クローン) を反復処理できます。

List<String> copy = new ArrayList<String>(list);
for (String s : copy) {
    // And if you have to add an element to the list, add it to the original one:
    list.add("some element");
}

リストの反復中に新しい要素をリストに追加することさえできないことに注意してくださいConcurrentModificationException

于 2012-06-24T12:16:36.833 に答える
1

これを行うには、新しい空の tmp リストに要素を追加し、addAll(). これにより、大きなソース リストを不必要にコピーすることがなくなります。

OP の元のリストに数百万のアイテムが含まれているとどうなるか想像してみてください。しばらくの間、メモリを 2 倍消費します。

リソースを節約するだけでなく、この手法により、80 年代スタイルの for ループに頼ったり、場合によっては魅力的でない効果的な配列インデックスを使用したりする必要がなくなります。

于 2012-06-24T12:20:34.853 に答える