任何人都可以向我解释这个Java陷阱吗?

时间:2011-05-15 15:26:53

标签: java collections

这个小小的烦恼导致我失去了一个小时的睡眠,我不明白为什么。

我有一个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();
}

为什么?

6 个答案:

答案 0 :(得分:7)

您未指定无法正常工作的方式,但是当您在ArrayList循环中迭代for时删除当前索引i处的元素,集合的大小和后续元素的索引,这两者都会改变,这可能是您不期望的。

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

  

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

答案 1 :(得分:1)

ArrayList和conditionMet是什么类型的? 您不能将==的对象与方法.equals(您应该覆盖)进行比较。

编辑:(暂时没有完成Java而不是100%确定这是否正确,你应该测试它)

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

答案 2 :(得分:1)

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

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

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

希望对你有用。

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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

  

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

答案 5 :(得分:0)

在第一个for循环中,

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

条件; i < array.size();在最开始时进行评估,它将采用原始列表的大小。因此,当迭代它时,如果从中移除任何元素,则大小已减小,但您仍在迭代到原始大小,这显然是错误的。

在for for second循环中,

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

因为您正在使用迭代器,所以您正在检查列表中是否还有剩余元素。因此,你不会超越,它可以正常工作。

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