嵌套迭代列表,然后是最终删除

时间:2012-09-27 15:37:06

标签: java oop loops iterator

我正在尝试通过循环遍历列表(嵌套循环)进行迭代。请考虑以下代码:

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中实现同样的东西而不会抛出异常的循环?

7 个答案:

答案 0 :(得分: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);

答案 1 :(得分: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();
    }

  }

}

答案 2 :(得分: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++;
            }

答案 3 :(得分:0)

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

答案 4 :(得分: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
    }

我认为您也可以在从arraylist中删除元素后更改索引。

答案 5 :(得分: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 
    ...
}

答案 6 :(得分:0)

foreach java语法隐藏了一个迭代器但是隐藏它,就不可能在这个上调用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

保持最佳做法;)