【问题标题】:can anyone explain this Java gotcha to me?任何人都可以向我解释这个 Java 陷阱吗?
【发布时间】:2011-08-25 22:38:09
【问题描述】:

这个小烦恼让我失眠了一个小时,我不明白为什么。

我有一个 ArrayList 数组,我想对其进行迭代并有条件地删除项目。这是我的第一次尝试:

for (int i = 0; i < array.size(); i++) {
   if (array.get(i) == conditionMet) array.remove(i);
}

那没有用。以下是:

for (Iterator<T> i = array.iterator(); i.hasNext();) {
   if (i.next() == conditionMet) i.remove();
}

为什么?

【问题讨论】:

  • loop on list with remove 的可能重复项
  • 你应该包含你得到的异常,很可能是“线程中的异常“main”java.lang.IndexOutOfBoundsException”。

标签: java collections


【解决方案1】:

在第一个for循环中,

for (int i = 0; i < array.size(); i++) {
   if (array.get(i) == conditionMet) array.remove(i);
}

条件; i &lt; array.size(); 在一开始就被评估,它将占用原始列表的大小。因此,在对其进行迭代时,如果从中删除任何元素,则大小会减小,但您仍在迭代到原始大小,这显然是错误的。

在第二个循环中,

for (Iterator<T> i = array.iterator(); i.hasNext();) {
   if (i.next() == conditionMet) i.remove();
}

由于您使用的是迭代器,因此您正在检查列表中是否还有元素。因此您不会越界,它可以正常工作。

(您应该在问题中包含异常。“线程“main”java.lang.IndexOutOfBoundsException中的异常”)

【讨论】:

    【解决方案2】:

    除非通过迭代器完成,否则集合不喜欢在循环中删除成员。

    迭代器允许调用者在迭代期间以定义明确的语义从底层集合中移除元素。

    【讨论】:

      【解决方案3】:

      简单。在第二种情况下,i 是一个类型迭代器的类,而在第一种情况下,i 是一个整数。当您删除值时,在迭代时,索引会改变(基本上,跳过一个)。因此,每次删除时,都必须将 i 减一(for 循环将再次增加)。所以,将第一个修改为

      for (int i = 0; i < array.size(); i++) {
          if (array.get(i) == conditionMet) array.remove(i--);
      }
      

      【讨论】:

        【解决方案4】:

        问题在于您正在尝试更改您正在迭代的列表。如果你做了这样的事情:

        int listSize = array.size();
        for (int i = 0; i < list; i++) {
            if (array.get(i) == conditionMet) {
                array.remove(i);
                i--;
                listSize--;
            }
        }
        

        这样,您只是迭代到一个 int,而不是使用您在循环体中更改的 ArrayList 的大小,这是 Java 不允许的。

        希望对你有用。

        【讨论】:

          【解决方案5】:

          ArrayList 和 conditionMet 是什么类型? 您不能仅使用 .equals 方法(您应该重写)比较带有 == 的对象。

          编辑:(已经有一段时间没有使用 Java 了,也不能 100% 确定这是否正确,您应该对其进行测试)

          Iterator<E> it = list.getIterator();
          while(it.hasNext()) {
            E obj = it.next();
            if(obj.equals(VARIABLE)) {
              it.remove();
            }
          }
          

          【讨论】:

            【解决方案6】:

            您没有指定 它是如何工作的,但是当您在 for 循环中迭代 ArrayList 并删除元素时当前索引i、集合大小和后续元素的索引都发生了变化,这可能是您没有预料到的。

            来自ArrayList#remove(int index) 的文档:

            删除此列表中指定位置的元素。 将任何后续元素向左移动(从它们的索引中减去一个)

            【讨论】:

            • 勇敢的尝试没有什么好,但我不认为这是正在发生的事情。在第一个示例中,array.remove() 甚至从不删除元素。当我给它两个不同的条件时,它就坏了,第一个测试 i 处的元素是否唯一:if (array.indexOf(array.get(i)) != array.lastIndexOf(array.get(i))) 另一个从另一个函数返回一个布尔值:if (!(isCity(array.get(i))))
            • ...换句话说,如果您提到的文档在第一种情况下导致了错误(这可能是有道理的),我看不出它在第二种情况下会如何。
            • @ledhed2222 所以失败是应该删除的元素(因为它们通过了条件测试)没有被删除?并且在第二种情况下使用相同的条件语句?你能发布失败的实际代码吗?这可能无关紧要,但ArrayList 中的数据类型是什么?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-31
            • 2011-08-19
            • 2016-06-16
            相关资源
            最近更新 更多