1

これは私の前の質問へのフォローアップです:

コレクション - Iterator.remove() 対 Collection.remove()

以下の 2 つのコードは、1 行だけ異なっているように見えますが、1 つは例外をスローし、もう 1 つは例外をスローしません。違いを説明していただけますか?

 List<String> list = new ArrayList<String>
(Arrays.asList("noob1","noob2","noob3"));


System.out.println(list);

for (String str : list) {
    if (str.equals("noob2")) {
        list.remove(str);
    }
}

正常に動作しますが、条件を変更すると

if (!str.equals("noob2"))

コードは例外をスローします!

4

6 に答える 6

5

この状況で何が起こるかは、2番目のリスト要素を削除することです。

List<String> list = new ArrayList<String>
        (Arrays.asList("noob1", "noob2", "noob3", "noob4"));

System.out.println(list);

for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String str = iterator.next();
    if (str.equals("noob3")) {
        System.out.println("Checking "+str);
        list.remove(str);
    }
}
System.out.println(list);

プリント

[noob1, noob2, noob3, noob4]
Checking noob1
Checking noob2
Checking noob3
[noob1, noob2, noob4]

最後から2番目の要素を削除することにより、サイズを繰り返した要素の数に減らしました。

// from ArrayList.Itr
    public boolean hasNext() {
        return cursor != size;
    }

これにより、で同時変更チェックが実行される前に、ループが早期に終了しnext()ます。他の要素を削除するnext()と、が呼び出され、CMEが取得されます。

ところで、チェックをバイパスするものは

for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String str = iterator.next();
    System.out.println("Checking "+str);
    if (str.equals("noob2")) {
        list.remove("noob1");
        list.remove("noob3");
    }
}

コレクションのサイズが最大のインデックスと同じである限り、チェックは実行されません。

于 2013-01-08T15:24:48.413 に答える
1

実際には、「カジュアル」な反復中にコレクションの要素を削除しないでください。いくつかのループでコレクションを変更する必要がある場合はiterator、これらの操作を行うために使用する必要があります。

    public class Test {
        public static void main(String... args) {
            List<String> list = new ArrayList<String>(Arrays.asList("noob1", "noob2", "noob3"));

            System.out.println(list);

            for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
                String str = iterator.next();
                if (!str.equals("noob2")) {
                    iterator.remove();
                }
            }
            System.out.println(list);
        }
    }
于 2013-01-08T15:29:31.140 に答える
1

for ループは、リストのイテレータ スキャンの簡略化された構文です。リストが変更された場合、反復子は例外をスローする場合がありますが、保証されていません。hasNext のおかげで、イテレータは多くの場合、1 つ先の要素を処理しているため、最初のケースがリストの変更による影響を受ける可能性が低くなります。「noob2」が削除されるまでに、イテレータは「noob3」についてすでに認識しています。

于 2013-01-08T15:23:51.763 に答える
1

ループしているコレクションを変更しようとしているために例外がスローされたと思います...if条件のためではありません。

状態を確認できるアイテムのみを含む新しいリストを作成することをお勧めします。それらを新しいリストに追加し、元のコレクションを変更しないようにします。

于 2013-01-08T15:23:53.597 に答える
1

これCollectionは、現在繰り返し処理している から削除しようとしているからです。マイナーな変更を加えて、やりたいことを実行できます。

 String[] strValues = {"noob1","noob2","noob3"}; // <<< Array
 List<String> list = new ArrayList<String>(Arrays.asList(strValues));

 System.out.println(list);

 for (String str : strValues) { // << List is duplicate of array so can iterate through array
     if (!str.equals("noob2")) {
         list.remove(str);
     }
 }

それはうまくいくはずです。うまくいけば

于 2013-01-08T15:32:36.413 に答える
0

インデックス 1 の要素を削除すると、イテレータはインデックス 2 の Iterator.hasNext() に対して false を返すため、最初のケースでは例外がスローされません。

Iterator<String> itr = list.iterator();
    while(itr.hasNext()){
        String s= itr.next();
        if(s.equals("noob2")){
            list.remove(s); // size of the list is 2 here 
            System.out.println(itr.hasNext());// this returns false as it doesn't have anything at index 2 now.(on 2nd iteration )
        }
    }

単純な for ループを使用して明確にテストできます。

for (int i=0; i<list.size(); i++) {
        if (list.get(i).equals("noob2")) {
            System.out.println(list.get(i));
            System.out.println(list.size());
            list.remove(list.get(i));
            System.out.println(list.size());
        }
    }

出力:

[noob1, noob2, noob3]
noob2
3
2

要素を削除した後のリストのサイズに注意してください。これは、インクリメント後に失敗します。2<2これは偽です

于 2013-01-08T15:33:32.740 に答える