在迭代Java时从数组中删除对象

时间:2017-06-10 15:46:55

标签: java arraylist foreach iterator

我试图在碰撞时删除船只和弹丸。 要做到这一点,我正在迭代两个高级的for循环,我尝试在它们相交时删除它们。不幸的是,迭代for循环而迭代它们并不是一个好主意,它会抛出一个ConcurrentModificationException,所以我将它们切换为Iterators,这似乎正在起作用。

public void collision()
{
    Iterator<Ship> itShips = Ship.ships.iterator();
    Iterator<Projectile> itProj = Projectile.projectiles.iterator();

    while (itShips.hasNext()) {
        Ship ship = itShips.next();

        while (itProj.hasNext()) {
            Projectile proj = itProj.next();

            if (ship.c != proj.c) {
                Rectangle.Float r1 = ship.getBounds();
                Rectangle.Float r2 = proj.getBounds();

                if (r1.intersects(r2)) {
                    itProj.remove();
                    itShips.remove();
                    break;
                }
            }
        }
    }
}

问题是ConcurrentModificationException似乎已移动到我调用更新程序的位置。我尝试将这些for循环交换为迭代器,但它似乎不起作用并抛出相同的异常,但现在在update()方法中。

public void update()
{   
    Iterator<Ship> it1 = Ship.ships.iterator();
    while (it1.hasNext()) {
        Ship s = it1.next();
        s.update(game);
    }

    Iterator<Projectile> it2 = Projectile.projectiles.iterator();
    while (it2.hasNext()) {
        Projectile p = it2.next();
        p.update(game);
    }
}

我是否应该更改我更新游戏对象的方式或保存方式?或者我是以错误的方式删除对象?

4 个答案:

答案 0 :(得分:2)

您可以保存碰撞到某个变量的那些,然后在完成循环后,从列表中删除它们:

Ship shipToRemove = null;
Projectile projToRemove = null;

Iterator<Ship> itShips = Ship.ships.iterator();
Iterator<Projectile> itProj = Projectile.projectiles.iterator();

while (itShips.hasNext()) {
    Ship ship = itShips.next();

    while (itProj.hasNext()) {
        Projectile proj = itProj.next();


        if (ship.c != proj.c) {
            Rectangle.Float r1 = ship.getBounds();
            Rectangle.Float r2 = proj.getBounds();

            if (r1.intersects(r2)) {
                shipToRemove = ship;
                projToRemove = proj;
                break;
            }
        }
    }
}

Projectile.projectiles.remove(projToRemove);
Ship.ships.remove(shipToRemove);

应该做什么。

答案 1 :(得分:0)

Iterator在迭代时不支持添加。在集合迭代器中使用expectedModCount来检查它是否被其他人修改。当你使用set reference modCount值进行一些add时,并且expectModCount没有改变导致异常。

您应该在最后跟踪并执行更新操作。

if (modCount != expectedModCount)
                throw new ConcurrentModificationException();




 public interface Iterator {

    boolean hasNext();

    E next();

    void remove();
    }

答案 2 :(得分:0)

解决问题的一种有效方法是filter非碰撞船只和射弹。这种方法避免了同时改变多个对象所引起的问题。我假设Ship.shipsProjectile.projectilesList个对象,并且可以使用这些对象代替它们的迭代器:

List<Ship> ships = Ship.ships;
List<Projectile> projs = Projectile.projectiles;

Stream<Rectangle.Float> shipBounds = ships.stream().map(s -> s.getBounds());
Stream<Rectangle.Float> projBounds = projs.stream().map(p -> p.getBounds());

List<Ship> safeShips = ships
        .stream()
        .filter(s -> !projBounds.anyMatch(p -> p.intersects(s.getBounds())))
        .collect(Collectors.toList());

List<Projectile> safeProjs = projs
        .stream()
        .filter(p -> !shipBounds.anyMatch(s -> s.intersects(p.getBounds())))
        .collect(Collectors.toList());

答案 3 :(得分:0)

由于我的update()方法仍然出错,我将collidedObjects存储在数组中。使用这些数组我可以从原始的Ship和Projectile数组中删除它们。我这样做是通过调用update()方法中的另一个方法来比较和删除对象。

[
  {
    "id": 1,
    "name": "name",
    "description": "description",
    "tag": [
      "tag1",
      "tag2",
      "tag3"
    ]
  }
]