【问题标题】:Nested iterating through list followed by an eventual deletion嵌套迭代列表,然后最终删除
【发布时间】:2012-09-19 10:55:02
【问题描述】:

我正在尝试遍历一个列表,同时已经在遍历它(嵌套循环)。考虑下面的代码:

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 中构造一个实现相同目的的循环而不抛出异常?

【问题讨论】:

  • 对问题标题的任何建议都非常感谢。

标签: java oop loops iterator


【解决方案1】:

当您迭代 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);

【讨论】:

  • Err ...不应该是del.add(n)吗?
  • 这是我正在寻找的,但是,我需要在 while 循环完成后立即删除元素,也就是说,在每个 for 循环结束时..跨度>
  • @Zar 你也可以这样做。只需将del 列表声明移动到循环内并在每次迭代后删除即可。
【解决方案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();
    }

  }

}

【讨论】:

    【解决方案3】:

    您得到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++;
                }
    

    【讨论】:

    • 问题是我需要使用列表中的数字进行比较。因此,i=1 ; i++ 不会这样做,因为数字不是 1、2、3 等
    • 你正在使用迭代器获取列表中的数字,那你为什么需要 for 循环?
    • 我正在学习 Java,但迭代器不会遍历项目(在本例中为列表)的值吗?我需要对每个列表值进行循环,这迫使我使用嵌套循环。
    • 这是否意味着列表中的每个项目都是另一个列表或什么?
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      我做了一些和你很相似的事情。看看这段代码。

      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
          }
      

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

      【讨论】:

        【解决方案6】:

        我没有尝试过,但都可以使用:

        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 
            ...
        }
        

        【讨论】:

        • 第一个解决方案仍然抛出 ConcurrentModificationException :-(
        【解决方案7】:

        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

        最好保持;)

        【讨论】:

          猜你喜欢
          • 2011-10-14
          • 1970-01-01
          • 1970-01-01
          • 2018-11-09
          • 1970-01-01
          • 2016-12-27
          • 1970-01-01
          • 2023-03-20
          • 2017-10-24
          相关资源
          最近更新 更多