以下代码导致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的意思是一件事,而且只有一件事:
- 您在集合C中创建了一个迭代器I(而
for (T a : c)
正在创建c
的迭代器( - 在稍后的某个时间点,集合C以某种方式进行了修改(而不是通过迭代器I的
.remove()
方法( - 你可以以任何方式与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亿——这取决于你想做什么。