使用foreach异常从arraylist中删除对象仅在列表大小超过2时发生

时间:2013-11-18 04:19:18

标签: java arraylist

我有以下类用于检查通过使用foreach循环从arraylist中删除对象

import java.util.ArrayList;

    public class CheckArrayList {
        /**
         * @return the a
         */
        public int getA() {
            return a;
        }

        /**
         * @param a
         *            the a to set
         */
        public void setA(int a) {
            this.a = a;
        }

        /**
         * @return the b
         */
        public int getB() {
            return b;
        }

        /**
         * @param b
         *            the b to set
         */
        public void setB(int b) {
            this.b = b;
        }

        int a;
        int b;

        public static void main(String[] args) {
            try {
                CheckArrayList checkArrayList1 = new CheckArrayList();
                checkArrayList1.setA(10);
                checkArrayList1.setB(20);

                CheckArrayList checkArrayList2 = new CheckArrayList();
                checkArrayList2.setA(30);
                checkArrayList2.setB(40);

                ArrayList<CheckArrayList> aList = new ArrayList<CheckArrayList>();

                aList.add(checkArrayList1);
                aList.add(checkArrayList2);

                System.out.println("size of list before iterate = " + aList.size());
                for (CheckArrayList checkArrayList : aList) {
                    aList.remove(checkArrayList);
                    System.out.println("inside loop");
                }
                System.out.println("size of list after iterate = " + aList.size());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

在执行上述操作时,它没有显示任何异常,但它只在循环中出现一次。

如果我向ist添加一个对象并执行相同操作,则显示java.util.ConcurrentModificationException

import java.util.ArrayList;

public class CheckArrayList {
    /**
     * @return the a
     */
    public int getA() {
        return a;
    }

    /**
     * @param a
     *            the a to set
     */
    public void setA(int a) {
        this.a = a;
    }

    /**
     * @return the b
     */
    public int getB() {
        return b;
    }

    /**
     * @param b
     *            the b to set
     */
    public void setB(int b) {
        this.b = b;
    }

    int a;
    int b;

    public static void main(String[] args) {
        try {
            CheckArrayList checkArrayList1 = new CheckArrayList();
            checkArrayList1.setA(10);
            checkArrayList1.setB(20);

            CheckArrayList checkArrayList2 = new CheckArrayList();
            checkArrayList2.setA(30);
            checkArrayList2.setB(40);

            CheckArrayList checkArrayList3 = new CheckArrayList();
            checkArrayList3.setA(30);
            checkArrayList3.setB(40);

            ArrayList<CheckArrayList> aList = new ArrayList<CheckArrayList>();

            aList.add(checkArrayList1);
            aList.add(checkArrayList2);
            aList.add(checkArrayList3);

            System.out.println("size of list before iterate = " + aList.size());
            for (CheckArrayList checkArrayList : aList) {
                aList.remove(checkArrayList);
                System.out.println("inside loop");
            }
            System.out.println("size of list after iterate = " + aList.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果arralist大小等于2,为什么它不显示异常?

2 个答案:

答案 0 :(得分:3)

要回答为什么它不会在2个元素上抛出错误,你必须看看每个循环实际上做了什么。for(Type something:myList)编译成如下:

Iterator<Type> iter = myList.iterator();
while(iter.hasNext()){
     Type something= iter.next()
     //your code
}

现在查看实际实现的ArrayList源代码。 hasNext()的代码是:

return cursor != size; //cursor is the current position in the list

因此,当您删除循环中的元素时,size现在为1.当它查看是否有更多元素时,它将返回false,因为它认为它位于ArrayList的末尾,并且此时停止执行循环。

现在查看next()的代码:

public E next() {
        checkForComodification();
        //more code
}

这是实际检查修改的地方,所以当size为3时,它将执行第二次迭代,当它调用next()来获取第二个元素时,它会抛出异常因为你修改了迭代器之外的ArrayList。

答案 1 :(得分:2)

您必须使用Iterator接口来完成此任务。

Iterator iterator = aList.iterator();
while(iterator.hasNext) {
     CheckArrayList obj = iterator.next();
     // use some condition to check which object to remove
     if(condition) {
          iterator.remove();
     }
}

编辑:回答您的编辑。 您正在迭代列表从0到SIZE,并在循环中删除项目(已经违反了最佳实践)。此删除操作会减小列表的大小,当您尝试访问大于有效大小的索引(删除项目后的大小)时,该列表将失败。

来自Java文档

  

此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出一个ConcurrentModificationException。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒着任意的,非确定性行为的风险。

希望这有帮助。