使用迭代器时并发修改异常? (JAVA)

时间:2015-06-17 18:47:19

标签: java debugging arraylist iterator

我正在尝试为模拟WaTor编写代码,其中鲨鱼和鱼互相吃掉并模拟群体控制等。无论如何,我遇到的问题是即使使用迭代器我仍然会得到一个concurrect修改异常。

这是我的代码:

private void updateSharks() {   
    for(Iterator<Shark> sharkit = sharks.iterator(); sharkit.hasNext();) {
        Shark sharky = sharkit.next();
        if(sharky.hasStarved()) {
            sharkit.remove();
        }
        else if(sharky.canBreed()) {
            addNewShark(sharky.getX(),sharky.getY());
        }
        moveShark(sharky);
    }
}

以下是例外:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at WaTor.Ocean.updateSharks(Ocean.java:281)
at WaTor.Ocean.update(Ocean.java:307)
at WaTor.Main.main(Main.java:13)

海洋中的第281行是“Shark sharky = sharkit.next();”谢谢你的帮助!

4 个答案:

答案 0 :(得分:2)

在遍历列表时无法修改列表。 如果您在遍历时从列表中删除元素 - 修复它的一个选项是将这些元素放在另一个列表中,然后循环遍历该列表以删除元素。 - 其他选项是使用Iterator.remove() 您正在使用Iterator.remove()。这很好。

如果您在遍历时添加元素也可能是个问题。我还没有测试过您的代码。但请确保您没有在方法addNewSharks()和moveSharks()

中向列表鲨鱼添加元素

答案 1 :(得分:0)

请查看Iterator的JavaDoc。对于remove方法,您可以找到以下文本:

  

从底层集合中移除此迭代器返回的最后一个元素(可选操作)。每次调用next()时,只能调用此方法一次。如果在迭代正在进行的过程中以除了调用ths方法之外的任何方式修改底层集合,则未指定迭代器的行为。

对我来说,看起来你正在迭代它时向集合中添加元素。因此,您可能会遇到未指定的行为。

答案 2 :(得分:0)

正如其他人提到的,你不能在迭代时修改集合(删除是可选的)。好吧,你可以收集所有应该死在另一个集合中的鲨鱼,并在迭代器循环结束后删除它们。

尝试以下方法:

private void updateSharks() { 
    ArrayList<Shark> toRemove = new ArrayList<Shark>();
    ArrayList<Shark> toAdd = new ArrayList<Shark>();

    for(Iterator<Shark> sharkit = sharks.iterator(); sharkit.hasNext();) {
        Shark sharky = sharkit.next();
        if(sharky.hasStarved()) {
            toRemove.add(sharky);
        }
        else if(sharky.canBreed()) {
            toAdd.add(/*create new shark object here*/)
        }
        moveShark(sharky);
    }

    for (Shark shark : toRemove) {
        sharks.remove(shark);
    }
    for (Shark shark: toAdd) {
        sharks.add(shark);
    }
}

编辑:工作原理

您正在遍历该集合。在此步骤中,您可以在集合中包含的对象中执行任何操作,但是您无法更改集合本身,因为迭代器不允许您这样做。

所以你创建了第二个临时集合。每次遇到要从主集合中删除的对象时,都会将此对象添加到临时集合中。因为在Java中只传递引用,并且此处没有深度复制,并且它是同时包含在两个集合中的同一对象。

现在,当迭代结束时,您拥有临时集合中包含的所有对象(或其引用,如果您更愿意这样考虑)。因为迭代器已经消失,所以没有任何东西限制你从主集合中删除所有这些对象,并且很容易完成!

答案 3 :(得分:0)

不要使用迭代器。像这样向后迭代集合:

import java.util.ArrayList;

public class RemoveFromCollectionExample {

    //
    // instance variables
    //

    private ArrayList<Shark> sharks;

    //
    // main
    //

    public static void main(String[] args) {
        RemoveFromCollectionExample example = new RemoveFromCollectionExample();
        example.sharks = new ArrayList<RemoveFromCollectionExample.Shark>();
        example.addShark(false, false, 0, 0);
        example.addShark(false, false, 0, 0);
        example.addShark(false, false, 0, 0);
        example.addShark(false, false, 0, 0);
        example.addShark(false, false, 0, 0);
        example.addShark(false, false, 0, 0);
        example.addShark(false, true, 0, 0);
        example.addShark(true, false, 0, 0);
        example.addShark(true, false, 0, 0);
        example.addShark(true, false, 0, 0);
        System.out.println("START WITH: " + example.sharks.size());
        example.updateSharks();
        System.out.println("Added 1, Removed 3");
        System.out.println("ENDED WITH: " + example.sharks.size());
    }

    //
    // update sharks
    //

    private void updateSharks() {
        for (int i = this.sharks.size() - 1; i > 0; i--) {
            Shark sharky = this.sharks.get(i);
            if (sharky.hasStarved()) {
                this.sharks.remove(i);
                System.out.println("REMOVED");
            } else if (sharky.canBreed()) {
                addNewShark(sharky.getX(), sharky.getY());
                System.out.println("ADDED");
            }
            moveShark(sharky);
        }
    }

    //
    // add new shark method
    //

    private void addNewShark(int x, int y) {
        this.sharks.add(new Shark(false, false, x, y));
    }

    private void addShark(boolean hasStarved, boolean canBreed, int x, int y) {
        this.sharks.add(new Shark(hasStarved, canBreed, x, y));
    }

    //
    // move method
    //

    private void moveShark(Shark sharky) {
    }

    //
    // Shark class
    //

    private class Shark {

        private boolean hasStarved;
        private boolean canBreed;
        private int x;
        private int y;

        public boolean hasStarved() {
            return hasStarved;
        }

        public void setHasStarved(boolean hasStarved) {
            this.hasStarved = hasStarved;
        }

        public boolean canBreed() {
            return canBreed;
        }

        public void setCanBreed(boolean canBreed) {
            this.canBreed = canBreed;
        }

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }

        public Shark(boolean hasStarved, boolean canBreed, int x, int y) {
            super();
            this.hasStarved = hasStarved;
            this.canBreed = canBreed;
            this.x = x;
            this.y = y;
        }

        public void moveShark() {
        }

    }

}
相关问题