删除对象导致冻结
Removing an object is causing freezes
[为了澄清,'monsters' 是一个 NPC 列表,当被物体射击时 'bullet' 从列表中删除。 ]
开始时出错:
W/System.err: java.util.ConcurrentModificationException
W/System.err: at java.util.ArrayList$Itr.next(ArrayList.java:831)
W/System.err: at com.companyname.product.GameplayScene.update(GameplayScene.java:113)
//...
我相信这意味着它正在尝试对列表中不存在的内容执行操作。所以我的问题是,我能否得到一些帮助,以确定一个对象被调用的点不存在,因为我似乎找不到它。我知道它在哪个 class 中,因为每个错误的第一行都会引用它。
for (Bullet bullet : player.getList())
if (npcManager.bulletCollide(bullet)) { //checks for a collision between all npcs and all bullets
player.getList().remove(bullet);//npc is removed in method above
}
if (!gameOver) {
npcManager.update(); //updates movement of npcs
if (npcManager.playerCollideNPC(player)) {
//end game
}
}
for (RectNPC NPC : npcManager.getList())
if (obstacleManager.NPCCollide(NPC)) { //checks collision between npcs and other objects
//
}
int i = 0;
//checks collisions between NPCs themselves
while (i < (Constants.NUMBER_ENEMIES - 1)) {
if (npcManager.getList().size() <= 1)
return;
if (Rect.intersects(npcManager.getList().get(i).getRectangle(), npcManager.getList().get(i + 1).getRectangle()))
npcManager.getList().get(i).setRectangle(200);
i += 1;
}
}
(上图)我想问题在于在对象不再可用的更新(如上所示)中调用某些内容,我删除 NPC 的方式是否有任何问题?
public boolean bulletCollide(Bullet bullet) {
for(RectNPC npc : monsters) {
if(npc.bulletCollideNPC(bullet)) {
monsters.remove(npc);
monsters.add(0, new RectNPC(new Rect(100, 100, 200, 200), Color.rgb(255, 0, 0), 25));
return true;
}
}
return false;
}
(以上)我删除 NPC 的代码,我已经包括在内,以防它有帮助 - 但是它确实做了它的意思,所以我不认为这是问题所在。
我的主要问题是,这里是否有任何东西会导致此错误(游戏停止几帧并在顶部给出错误)- 或者是否有 something/somewhere 具体我应该在看?我也知道我的一些语法不是很好,很抱歉这是我的第一个 Java 项目。
当前迭代器:
for(Iterator<RectNPC> iterator = monsters.iterator(); iterator.hasNext();) {
if(iterator.next().bulletCollideNPC(bullet)) {
iterator.remove();
monsters.add(0, new RectNPC(new Rect(100, 100, 200, 200), Color.rgb(255, 0, 0), 25));
return true;
}
}
和
for (Iterator<Bullet> iterator = player.getList().iterator(); iterator.hasNext(); ) {
if (npcManager.bulletCollide(iterator.next())) {
iterator.remove();
//
}
}
在 java 中,您不能执行 for( T variable : collection ) { collection.remove( variable ); }
换句话说,您不能从使用 for
循环迭代的集合中删除项目。它将导致 ConcurrentModificationException
。 Google for "java fail-fast iterator" 了解有关原因和方式的更多信息。
您有两个选择:
将所有要移除的怪物收集到一个临时列表中,然后在完成对主列表的迭代后,再次迭代临时列表以将它们从主列表中移除。关键是您不会从正在迭代的同一个列表中删除。
而不是 "foreach" (for
) 循环,使用实际的迭代器,当你想删除一个项目时,通过调用迭代器的 remove()
方法, 不是 包含集合的 remove()
方法。迭代器的 remove()
方法使用必要的技巧来防止 ConcurrentModificationException
被抛出。
您的方法正在做 3 件不同的事情。它返回一个布尔值,从列表中删除一个元素,然后添加一个元素。我会重组代码,以便您有 3 个方法只做 1 件事。
您可以使用 Java 8 内部迭代器的强大功能作为起点
monsters.removeIf(e -> e.bulletCollideNPC(bullet));
使用迭代器以安全的方式移除元素。
Note that Iterator.remove is the only safe way to modify a collection
during iteration; the behavior is unspecified if the underlying
collection is modified in any other way while the iteration is in
progress.
From Java SE documentation
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
例子
[为了澄清,'monsters' 是一个 NPC 列表,当被物体射击时 'bullet' 从列表中删除。 ]
开始时出错:
W/System.err: java.util.ConcurrentModificationException
W/System.err: at java.util.ArrayList$Itr.next(ArrayList.java:831)
W/System.err: at com.companyname.product.GameplayScene.update(GameplayScene.java:113)
//...
我相信这意味着它正在尝试对列表中不存在的内容执行操作。所以我的问题是,我能否得到一些帮助,以确定一个对象被调用的点不存在,因为我似乎找不到它。我知道它在哪个 class 中,因为每个错误的第一行都会引用它。
for (Bullet bullet : player.getList())
if (npcManager.bulletCollide(bullet)) { //checks for a collision between all npcs and all bullets
player.getList().remove(bullet);//npc is removed in method above
}
if (!gameOver) {
npcManager.update(); //updates movement of npcs
if (npcManager.playerCollideNPC(player)) {
//end game
}
}
for (RectNPC NPC : npcManager.getList())
if (obstacleManager.NPCCollide(NPC)) { //checks collision between npcs and other objects
//
}
int i = 0;
//checks collisions between NPCs themselves
while (i < (Constants.NUMBER_ENEMIES - 1)) {
if (npcManager.getList().size() <= 1)
return;
if (Rect.intersects(npcManager.getList().get(i).getRectangle(), npcManager.getList().get(i + 1).getRectangle()))
npcManager.getList().get(i).setRectangle(200);
i += 1;
}
}
(上图)我想问题在于在对象不再可用的更新(如上所示)中调用某些内容,我删除 NPC 的方式是否有任何问题?
public boolean bulletCollide(Bullet bullet) {
for(RectNPC npc : monsters) {
if(npc.bulletCollideNPC(bullet)) {
monsters.remove(npc);
monsters.add(0, new RectNPC(new Rect(100, 100, 200, 200), Color.rgb(255, 0, 0), 25));
return true;
}
}
return false;
}
(以上)我删除 NPC 的代码,我已经包括在内,以防它有帮助 - 但是它确实做了它的意思,所以我不认为这是问题所在。
我的主要问题是,这里是否有任何东西会导致此错误(游戏停止几帧并在顶部给出错误)- 或者是否有 something/somewhere 具体我应该在看?我也知道我的一些语法不是很好,很抱歉这是我的第一个 Java 项目。
当前迭代器:
for(Iterator<RectNPC> iterator = monsters.iterator(); iterator.hasNext();) {
if(iterator.next().bulletCollideNPC(bullet)) {
iterator.remove();
monsters.add(0, new RectNPC(new Rect(100, 100, 200, 200), Color.rgb(255, 0, 0), 25));
return true;
}
}
和
for (Iterator<Bullet> iterator = player.getList().iterator(); iterator.hasNext(); ) {
if (npcManager.bulletCollide(iterator.next())) {
iterator.remove();
//
}
}
在 java 中,您不能执行 for( T variable : collection ) { collection.remove( variable ); }
换句话说,您不能从使用 for
循环迭代的集合中删除项目。它将导致 ConcurrentModificationException
。 Google for "java fail-fast iterator" 了解有关原因和方式的更多信息。
您有两个选择:
将所有要移除的怪物收集到一个临时列表中,然后在完成对主列表的迭代后,再次迭代临时列表以将它们从主列表中移除。关键是您不会从正在迭代的同一个列表中删除。
而不是 "foreach" (
for
) 循环,使用实际的迭代器,当你想删除一个项目时,通过调用迭代器的remove()
方法, 不是 包含集合的remove()
方法。迭代器的remove()
方法使用必要的技巧来防止ConcurrentModificationException
被抛出。
您的方法正在做 3 件不同的事情。它返回一个布尔值,从列表中删除一个元素,然后添加一个元素。我会重组代码,以便您有 3 个方法只做 1 件事。
您可以使用 Java 8 内部迭代器的强大功能作为起点
monsters.removeIf(e -> e.bulletCollideNPC(bullet));
使用迭代器以安全的方式移除元素。
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress. From Java SE documentation
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
例子