【问题标题】:Why arrayList is not iterating at last element? [duplicate]为什么 arrayList 不在最后一个元素处迭代? [复制]
【发布时间】:2016-12-09 12:24:56
【问题描述】:

我尝试了以下两种情况:

    ArrayList arrayList = new ArrayList();
    arrayList.add("1");
    arrayList.add("2");
    arrayList.add("3");

    Iterator iterator = arrayList.iterator();
    while (iterator.hasNext()) {

        String value = (String) iterator.next();
        System.out.println("---->" + value);
        if (value.equals("1")) {
            arrayList.remove(0);
        }
    }

第一个场景输出是:

---->1
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at Test.main(Test.java:83)

ConcurrentModificationException 异常可能是因为我试图修改集合而我仍在迭代它。

在第二种情况下,我将if() 条件从value.equals("1") 更改为value.equals("2"),并且程序没有抛出任何错误。

ArrayList arrayList = new ArrayList();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");

Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {

    String value = (String) iterator.next();
    System.out.println("---->" + value);
    if (value.equals("2")) {
        arrayList.remove(0);
    }
}

第二个场景输出是:

---->1
---->2

在这两种情况下,我的程序都没有到达第三个元素(值:3)。

你能帮我理解这个问题吗?

【问题讨论】:

  • arrayList.remove(0); 是您的问题。请改用iterator 对象来删除元素。
  • @Jonk 我知道它会通过调用迭代器对象的 remove 方法来避免错误。但我想了解为什么在第二种情况下没有达到第三个元素?
  • 这是因为在索引 0 处删除后元素 3 变为第二个,因此已被视为迭代;它不会抛出异常,因为不能保证快速失败的行为 - 请参阅可能的重复项。

标签: java arraylist collections


【解决方案1】:

问题是您要从列表中删除索引为 0 的元素。而不是从列表中删除,请使用 iterator.remove() 方法。更多信息请阅读this

程序代码-

List arrayList = new ArrayList();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");

Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
   String value = (String) iterator.next();
   System.out.println("---->" + value);
   if (value.equals("2")) {
      iterator.remove();
   }
}

为什么列表不返回最后一个元素?

回答 -

您正在从列表中删除元素,并且您已经对同一列表执行了迭代器操作。最后 iterator.hasnext() 方法返回 false 所以你没有得到最后一个元素。

如果您想查看它以进行演示,请运行以下示例代码 -

List arrayList = new ArrayList();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
    String value = (String) iterator.next();
    System.out.println("---->" + value);
    if (value.equals("2")) {
       arrayList.remove(0);
    }
}
System.out.println("ArrayList : "+arrayList);

输出 -

---->1

---->2

数组列表:[2, 3]

List arrayList = new ArrayList();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");

Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
      String value = (String) iterator.next();
      System.out.println("---->" + value);
      if (value.equals("2")) {
         iterator.remove();
      }
}
System.out.println("ArrayList : "+arrayList);

输出 -

---->1

---->2

---->3

数组列表:[1, 3]

【讨论】:

  • 我知道通过调用迭代器对象的remove方法可以避免错误。但我想了解为什么在第二种情况下没有达到第三个元素?
  • @Keval Pithva- 因为您正在从列表中删除元素并且您已经对同一列表执行了迭代器操作。最后 iterator.hasnext() 方法返回 false 所以你没有得到最后一个元素。
【解决方案2】:

通过在调试模式下运行两段代码,我发现了以下内容。

第一种情况:

从 arraylist 保存的元素:

删除命令执行后:

ConcurrentModificationException 在以下行被抛出

String value = (String) iterator.next();

第二个场景:

ArrayList 将与第二个链接相同。

打印2后,控制中断

while (iterator.hasNext())

作为iterator.hasNext() = null。因此它是安全的。

【讨论】:

    【解决方案3】:

    我想您只在第一种情况下遇到问题,因为您试图删除迭代器指向的元素。事实上,第二种情况成功了,因为您删除了第一个 arraylist 元素,此时迭代器并未指向该元素。

    (p.s. 我同意所有各种和未来的答案,这些答案将描述您如何通过显示代码片段来解决您的问题,我只是向您解释了发生的情况)

    【讨论】:

      【解决方案4】:

      ConcurrentModificationException 的出现是因为您正在删除当前循环迭代正在读取的相同元素(索引 0)(值 =“1”的元素)。在第二种情况下,您看不到异常,因为您正在删除索引 0 处的元素,但正在读取索引 1 处的元素(值为“2”的元素)。除非您使用支持并发的集合之一(请参阅java.util.concurrent 包),否则您不能在读取元素时同时删除它

      您在迭代列表时删除了一个元素 (remove(0)),这会将“列表的末尾”向左移动 1。因此,下次您检查 iterator.hasNext() 时,它将返回 false 并且原始的第三个元素永远不会被处理。

      【讨论】:

        【解决方案5】:

        当你对一个集合进行迭代时,你应该使用迭代器移除元素:

        iterator.remove()
        

        在第二个代码中,这里:

            if (value.equals("2")) {
                arrayList.remove(0);
            }
        

        您删除列表的第一个元素。该列表的大小为 2 个元素。
        迭代器实现会考虑列表的大小以了解它是否有下一个元素:

        public class ArrayList<E> extends AbstractList<E>
           ...
          private class Itr implements Iterator<E> {
        
          public boolean hasNext() {
              return cursor != size;
          }
        }
        

        由于迭代了两个元素,并且列表现在的大小为 2,因为您删除了其中的一个元素,因此迭代器认为它没有下一个要迭代的元素。

        如果你使用迭代器来移除当前元素,你就没有这个副作用。

        【讨论】:

        • Iterator.hasNext() 方法是否每次迭代集合时都会检查列表的大小?
        • 是的。它在 ArrayList 的实现中。我贴出来了。
        猜你喜欢
        • 2014-12-19
        • 2015-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-03
        • 2023-03-27
        • 1970-01-01
        相关资源
        最近更新 更多