在两个地方通过LinkedLinkst循环会产生错误

时间:2018-01-15 15:00:46

标签: java linked-list iteration

所以我在Java中制作一个小游戏,在游戏中你有实体存储在LinkedList中。在tick方法中,我遍历实体' LinkedList如下:

->weekly()->mondays()->at('14:32');

渲染方法也是如此

@Override
public void tick(float delta) {
    for (Entity e : entities) {
        e.tick(delta);
    }
    player.tick(delta);
}

其中一个实体是一个名为Block的类。在Block类中,有一个函数在块接近时返回,在此函数中我也遍历实体' LinkedList和它在Block中的以下tick方法调用:

@Override
public void render(Graphics g) {
    g.setColor(Color.DARK_GRAY);
    g.fillRect(0, 0, Game.WIDTH, Game.HEIGHT);
    for(Entity e : entities) {
        e.render(g);
    }
    player.render(g);
}

(顺便说一下,该函数在块的tick方法中调用并使用)

现在每次我运行游戏时,游戏都会启动并运行正常几毫秒,然后抛出此异常:

    @Override
public void tick(float delta) {
    if (color == Color.WHITE) {
        if (getSurrounding(-32, -32) != null && getSurrounding(-32, -32).getColor() == Color.BLACK) {
            if (getSurrounding(-32, -32).getStrength() < strength) {
                getSurrounding(-32, -32).setStrength(-50);
            }
        }
    }

    if (!inGame.entities.isEmpty() && strength <= 0) {
        inGame.entities.remove(this); // <------ REMOVING AN ELEMENT
    }
}

public Block getSurrounding(int xOffset, int yOffset) {
    for (Entity e : inGame.entities) {
        if (e instanceof Block) {
            if (x + xOffset == e.getX() && y + yOffset == e.getY()) {
                return (Block) e;
            }
        }
    }
    return null;
}

(前两个代码示例位于InGame.java文件中,第36行是tick方法中的for循环) 现在我该如何阻止此错误?

3 个答案:

答案 0 :(得分:3)

ConcurrentModificationException通常涉及在循环中迭代列表时修改列表。

我的假设是你在迭代时删除一个元素。

为了阻止这种情况发生,我建议在变量处于循环中时保存要删除的对象(并且已满足某些条件),然后在循环完成后将其从列表中删除。

编辑:根据更新的问题,您将删除tick方法中的元素。我不会在这里执行此操作,但返回您要删除的元素,并仅在您不再迭代要删除的列表时将其删除。

可能的解决方案: 我会创建另一个方法来检查实体的强度并从tick方法调用它(这是为了保存tick方法必须返回一个要删除的对象),如下所示:

@Override
public void tick(float delta) {
    Entity removeEntity = null;
    for (Entity e : entities) {
        e.tick(delta);
        if(e.checkStrength()){
           removeEntity = e;
           break;
        }
    }

    if(removeEntity != null){
       entities.remove(removeEntity);
    }

    player.tick(delta);
}

在实体类中:

public boolean checkStrength(){
    if (!inGame.entities.isEmpty() && strength <= 0) {
        return true;
    }
    return false;
}

您知道这不是目前为止最好的解决方案,但应该让您解决现在遇到的问题。有空的时候一定要清理你的代码。

答案 1 :(得分:1)

您正在删除tick()方法中的实体...在方法中,您仍在迭代外部tick方法中的实体...因为您正在修改{{{}内的列表1}},列表正在改变,导致下一次迭代失败...用inline方法将方法调用替换为e.tick()可以更清楚地证明问题:

e.tick()

请注意,您已经注意到的是&#34;删除元素&#34;在最外层循环中,这是导致问题的原因。

编辑:建议的解决方案正如其他人所建议的那样,尝试这样的事情(只显示删除块):

@Override
public void tick(float delta) {
    for (Entity e : entities) {
        //e.tick(delta); --inline below

          if (color == Color.WHITE) {
              if (getSurrounding(-32, -32) != null && getSurrounding(-32, -32).getColor() == Color.BLACK) {
                  if (getSurrounding(-32, -32).getStrength() < strength) {
                      getSurrounding(-32, -32).setStrength(-50);
                  }
              }
          }

          if (!inGame.entities.isEmpty() && strength <= 0) {
              inGame.entities.remove(this); // <------ REMOVING AN ELEMENT
          }
      }

}

然后在调用函数中,在完成所有迭代后

List toRemove = new ArrayList() //somewhere earlier in the code
if (!inGame.entities.isEmpty() && strength <= 0) {
    //inGame.entities.remove(this); // <------ REMOVING AN ELEMENT
    toRemove.add(this);
}
return toRemove;

答案 2 :(得分:0)

使用迭代器的解决方案:

用以下内容替换第一个代码块:

public void tick(float delta) {
    for (Iterator<Entity> iterator = entities.iterator(); iterator.hasNext();) {
      boolean remove = e.tick(delta);
      if(remove) {
          iterator.remove();
      }
    }
    player.tick(delta);
}

然后用其替换另一个tick方法:

public boolean tick(float delta) {
    if (color == Color.WHITE) {
        if (getSurrounding(-32, -32) != null && getSurrounding(-32, -32).getColor() == Color.BLACK) {
            if (getSurrounding(-32, -32).getStrength() < strength) {
                getSurrounding(-32, -32).setStrength(-50);
            }
        }
    }

    if (!inGame.entities.isEmpty() && strength <= 0) {
        return true;
    }
    return false;
}

这应该可以解决您的问题。方法返回类型必须更改,以便我们有一个指示器何时删除任何元素,何时不删除。每次tick返回true时,相应的元素都将被删除