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

您不能从正在迭代的列表中删除项目。一种选择是将您需要的项目添加到另一个列表中。最后,您列出了您需要的项目。或者您可以迭代原始列表的克隆。

于 2012-09-27T15:41:58.750 回答
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 回答
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,它不会。一个简单的 ackward 调用it.next()会以NoSuchElementException.

这是保持的最佳做法;)

于 2012-09-27T15:54:56.353 回答