由于增强的for循环,并发修改错误



以下代码导致Exception in thread "main" java.util.ConcurrentModificationException错误。

我正试图使用增强的for循环来迭代我的无人机ArrayList,以更新它们的位置和方向。以下代码仅适用于ArrayList中的1架无人机。

tryToMove()获取无人机的方向,将其移动到相应的x、y,并检查其是否有效,如果无效,则更改方向。

doDisplay()用控制台中的无人机打印竞技场。

public static void moveAllDrones(){
String strOfCurrentDirection;
Direction currentDirection;

for (String drone : drones) {
id = drones.indexOf(drone);
System.out.println("Working on drone: " + id);
String[] coords = drone.split(",");
accX = Integer.parseInt(coords[0]);//get x coordinate
accY = Integer.parseInt(coords[1]);// get y coordinate

String droneWithCurrentID = drones.get(id); //direction in string
strOfCurrentDirection = droneWithCurrentID.split(",")[2];
currentDirection = Direction.valueOf(strOfCurrentDirection); //convert string to direction


Drone.tryToMove(id, currentDirection, accX, accY);
}
DroneInterface.doDisplay();
}

我不知道为什么这个增强的for循环只适用于1架无人机。感谢您的帮助。

更新:

public static void tryToMove(int id2, Direction accDir, int x1, int y1) {
xPos = x1;
yPos = y1;
//Direction d = Drone.direction; // get current direction drone is facing.
System.out.println("Trying to move drone, "+id2+ ". In the direction of: "+accDir);
switch (accDir) {
case NORTH: 
yPos -= 1;
if (DroneArena.canMoveHere(xPos, yPos)) {
DroneArena.yRan = yPos;

} else {
yPos += 1;
accDir = Direction.nextDirection();
}
DroneArena.updateDrone(id2, accDir, xPos, yPos);
break;
case EAST:
xPos += 1;
if (DroneArena.canMoveHere(xPos, yPos)) {
DroneArena.xRan = xPos;

} else {
xPos -= 1;
accDir = Direction.nextDirection();
}
DroneArena.updateDrone(id2, accDir, xPos, yPos);
break;
case SOUTH:
yPos += 1;
if (DroneArena.canMoveHere(xPos, yPos)) {
DroneArena.yRan = yPos;
} else {
yPos -= 1;
accDir = Direction.nextDirection();
}
DroneArena.updateDrone(id2, accDir, xPos, yPos);
break;
case WEST:
xPos -= 1;
if (DroneArena.canMoveHere(xPos, yPos)) {
DroneArena.xRan = xPos;
} else {
xPos += 1;
accDir = Direction.nextDirection();
}
DroneArena.updateDrone(id2, accDir, xPos, yPos);
break;
}
}

更新无人机:

public static void updateDrone(int id2, Direction direction, int newX, int newY){
updatedDirection = direction;
DroneArena.direction = updatedDirection;
drones.remove(id2);
drones.add(id2, newX + "," + newY +"," + updatedDirection);
}

CoModEx的意思是一件事,而且只有一件事:

  1. 您在集合C中创建了一个迭代器I(而for (T a : c)正在创建c的迭代器(
  2. 在稍后的某个时间点,集合C以某种方式进行了修改(而不是通过迭代器I的.remove()方法(
  3. 你可以以任何方式与I交互:调用其中的任何方法,或者点击for (T a : c)循环(你到达循环的末尾,或者在循环中运行continue;

您在这里这样做:当您启动for循环时,您生成drones的迭代器,然后修改drones,然后迭代循环(因为tryToMove修改了无人机(。

你就是做不到,原因应该很明显:这到底意味着什么?如果您在[1, 2, 3, 4, 5]上迭代,并且在2的迭代过程中,您删除了3,那么3是否应该被跳过?如果在2的迭代过程中,您删除了1,该怎么办?如果3应该跳过,但1已经完成,不能跳过,这意味着什么?另外,试图跟踪被删除的内容是不平凡的(通常你只需要使用索引,但如果你在循环的中途开始删除以前的元素,那就变得很棘手了(,这也是为什么它会这样工作的第二个原因:当你迭代一个集合时,你不能修改它。

那么,你是如何解决的呢?

简单的方法是首先制作一个无人机的副本,然后在副本中迭代。这样,您在循环过程中所做的任何修改都不会影响您的副本,因此不会导致CoModExes。请注意,这当然意味着在循环过程中,您所做的任何修改都不可见。

第二个选项仅适用于数组列表或其他具有快速基于索引查找的构造,即使用旧样式的循环,并手动管理索引变量。

第三种方法是使用具有明确定义行为的集合类型(例如CopyOnWriteArrayList,它完成了列表中内置的第一个选项

第四个是重新设计你正在做的事情,这样修改基础集合就不再是它的一部分

第五种方法是在迭代过程中存储您想对列表执行的所有操作,然后将它们全部应用。

还有10亿——这取决于你想做什么。

相关内容

  • 没有找到相关文章

最新更新