4

既にループしている間にリストを反復処理しようとしています (ネストされたループ)。以下のコードを検討してください。

ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it

for(int i : list) { // ConcurrentModificationException

   Iterator iterator = list.iterator();

   while(iterator.hasNext()) {

      int n = iterator.next();

      if(n % i == 0) {
         iterator.remove();
      }

   }

}

上記の例では、ConcurrentModificationException が発生します。もちろん、要素を削除する条件は単なる例です。

私は何かが欠けていると確信しています。しかし、例外をスローせずにJavaで同じことを達成するループをどのように構築すればよいでしょうか?

4

7 に答える 7

5

list実行を繰り返すときに明らかに変更すると、実行が発生します。別のリストを使用して、削除する要素のリストを維持し、最後にそれらを削除できます。

ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it
ArrayList<Integer> del = new ArrayList<Integer>(); // Elements to be deleted

for(int i : list) { // ConcurrentModificationException
   Iterator iterator = list.iterator();
   while(iterator.hasNext()) {    
      int n = iterator.next();
      if(n % i == 0) {
          del.add(n);      
      }
   }
}

list.removeALL(del);
于 2012-09-27T15:48:08.220 に答える
2

リストのコピーに対して外側の反復を反復させます。

for (int i : new ArrayList<>(list)) {

  Iterator<Integer> iterator = list.iterator();

  while (iterator.hasNext()) {

    int n = iterator.next();

    if (n % i == 0) {
      iterator.remove();
    }

  }

}
于 2012-09-27T16:08:01.007 に答える
1

ループを実行してConcurrentModificationExceptionいるときに、forを変更しようとしているためlistです。

以下がエレガントな解決策であるかどうかはわかりませんが、以下のようなものが機能する可能性があります。

       Iterator<Integer> iterator = list.iterator();
            int i=1;
            while (iterator.hasNext()) {

                int n = iterator.next();

                if (n % i == 0) {
                    iterator.remove();
                }
                i++;
            }
于 2012-09-27T15:42:22.240 に答える
0

繰り返されているリストからアイテムを削除することはできません。1つのオプションは、必要なアイテムを別のリストに追加することです。最後に、必要なアイテムのリストがあります。または、元のリストのクローンを反復処理することもできます。

于 2012-09-27T15:41:58.750 に答える
0

foreachjava構文はイテレータを非表示にしますが、非表示にするため、このイテレータでremoveメソッドを呼び出すことはできません。

だから私はします:

ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it

int count = 0;
for(Iterator<Integer> it = list.iterator();it.hasNext();count++){ //increments count++
   Integer currentInt = it.next();
   if(currentInt % count == 0){
     it.remove();
   }
}

二次イテレータを必要とせずに同じ機能が実現されていることがわかります。

同じリストを同時に繰り返すことはできません。要約すると、modcount変数は、リストが並列に変更または繰り返されるたびに、それ自体の予期しない変更を検出するために使用されます。したがって、につながるConcurrentModificationException。これはマルチスレッド環境で非常に頻繁に発生し、開発者はそれを認識している必要があります。

さらに、コレクションを反復処理するには、ループのfor代わりにループを使用することをお勧めします。while

なんで ?

ちなみに、whileループ後もイテレータオブジェクトをスコープ内に置いたままにするのに対し、を使用しforた場合はそうではありません。への単純な厄介な呼び出しit.next()は、で終わるでしょうNoSuchElementException

維持することがベストプラクティスです;)

于 2012-09-27T15:54:56.353 に答える
0

私はあなたとかなり似たようなことをします。このコードを見てください。

out:for(int h=0; h<tempAl.size(); h++) {
                        if(tempAl.get(0).split("\\s")[0].equals("OFF")){
                            tempAl.remove(0);
                            h=-1;
                            continue;
                        }
                        if(tempAl.get(h).split("\\s")[0].equals("ON")){
                            ONTime= tempAl.get(h);
               ///rest fof the code
    }

配列リストから要素を削除した後、インデックスを変更することもできると思います。

于 2012-09-27T15:45:33.720 に答える
0

私は試していませんが、どちらかを使用します:

List<Integer> list = new ArrayList<Integer>(); 
// add some values to it  
for(Iterator<Integer> iterator1 = list.iterator(); iterator1.hasNext();) { 
    int i = iterator1.next();
    for(Iterator<Integer> iterator2 = list.iterator(); iterator2.hasNext();){
        int n = iterator.next();        
        if(n % i == 0) {          
            iterator2.remove();       
        }     
    }  
} 

または、これでも ConcurrentModificationException がスローされる場合 (同じリストに基づく 2 つの反復子を使用するとどうなるかわかりません)、次を使用します。

List<Integer> list = new ArrayList<Integer>(); 
// add some values to it  
for(int i : new ArrayList(list)){ // copy list 
    ...
}
于 2012-09-27T15:52:55.603 に答える