有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

删除元素时ArrayList hasNext的java行为

我正在删除数组中的元素,考虑下面的代码:

private static List<Person> persons = new ArrayList<>();
     //initialize the persons arraylist.

     for (Person p : persons) {
        if (p.getAge() < 18) {
            persons.remove(p);
        }
    }

初始化方法:

private static void initialize() {

    persons.add(new Person("Rahul", 25, Gender.MALE, Citizenship.INDIA));
    persons.add(new Person("Sally", 21, Gender.FEMALE, Citizenship.USA));
    persons.add(new Person("Ben", 35, Gender.MALE, Citizenship.CANADA));
    persons.add(new Person("Wayne", 30, Gender.MALE, Citizenship.UK));
    persons.add(new Person("ShaneYoung", 18, Gender.MALE, Citizenship.AUSTRALIA));
    persons.add(new Person("Kimmo", 17, Gender.MALE, Citizenship.FINLAND));
    persons.add(new Person("Simo", 17, Gender.MALE, Citizenship.FINLAND));

}

输出: [Rahul、Sally、Ben、Wayne、Shaneyong、Simo]

请注意,第二个和最后一个项目最好不要退回。 我理解,如果我们试图在遍历ArrayList时修改它的结构,我们可能会得到ConcurrentModificationException。我指的是ArrayList中的remove(对象o)。当然,这不是在迭代时删除元素的推荐方法。大多数情况下都会引发异常。但是,如果我有一个列表,其中最后一项满足我的删除条件,最后一项也满足删除条件,则不会抛出ConcurrentModificationException,因为hasNext方法返回false。hasNext()的代码是:

return cursor != size 

在这种情况下,游标==大小。但请注意,最后一个元素也被跳过或未被处理。因此,除了最后一个元素外,没有异常被跳过,但也会在输出中返回

我已经研究了thisbug,还研究了它所链接的重复bug。他们似乎强调了一个稍微不同的场景

当我们调用迭代器时。移除时,似乎将光标位置调整为lastRet。所以使用迭代器。即使使用满足移除条件的第二个和最后一个项目移除,也可以正常工作,但调用fastRemove的remove(对象o)似乎没有设置此项,因此完全跳过最后一个元素

我知道迭代器。删除javadoc中提到的未指定行为,上面提到的bug中提到的注释也表明ConcurrentModificationException是尽最大努力抛出的。但是考虑到上面的代码,最后一个元素没有被过滤掉,这不是一个bug还是一个应该以更好的方式处理的场景

我注意到了这里的另一个question,但答案只解释了在我上面提到的当前实现中如何实现输出。我的问题更多的是,是否应该更改hasNext实现来处理这种情况


共 (3) 个答案

  1. # 1 楼答案

    当你试图在循环过程中删除列表中的元素时,它会被监听。 我通常会声明另一个临时列表,这样就可以使用removeAll方法来创建它

    List<Person> temp = new List<Person>();
         for (Person p : persons) {
            if (p.getAge() < 18) {
                temp.add(p);
            }
          }
    
    persons.removeAll(temp);
    
  2. # 2 楼答案

    根据JLS #14.14.2,增强的for循环相当于使用迭代器

    正如你提到的,^{}的javadoc非常清楚:

    The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.

    所以不,这不是虫子

  3. # 3 楼答案

    您可以使用ListIterator删除这些项,因为它有一个remove方法:

    ListIterator<Person> iter = persons.listIterator();
    while (iter.hasNext()) {
        Person p = iter.next();
        if (p.getAge() < 18) {
            iter.remove();
        }
    }
    

    但我推荐assylias建议的Java 8解决方案:

    persons.removeIf(p -> p.getAge() < 18);