Java ConcurrentModificationException在尝试实现Dijkstra算法时发生
我试图在迷宫中实现Dijkstra的最短路径算法。 () 我得到了两个哈希集,一个用于访问的字段,另一个用于未访问的字段。 一旦一个字段被其所有邻居通过算法访问, 我想把它放在访问过的地图上,然后从未访问的地图上删除它 然而,当我尝试运行该算法时,我在Netbeans中得到一个ConcurrentModificationException 有趣的是——我已经读过这个问题,根据我的理解,这个问题来自于试图操纵/删除数据集中的数据,而不是通过迭代来解决。但是,我在集合的迭代中得到错误,即:Java ConcurrentModificationException在尝试实现Dijkstra算法时发生,java,hashset,concurrentmodification,Java,Hashset,Concurrentmodification,我试图在迷宫中实现Dijkstra的最短路径算法。 () 我得到了两个哈希集,一个用于访问的字段,另一个用于未访问的字段。 一旦一个字段被其所有邻居通过算法访问, 我想把它放在访问过的地图上,然后从未访问的地图上删除它 然而,当我尝试运行该算法时,我在Netbeans中得到一个ConcurrentModificationException 有趣的是——我已经读过这个问题,根据我的理解,这个问题来自于试图操纵/删除数据集中的数据,而不是通过迭代来解决。但是,我在集合的迭代中得到错误,即: for(
for( Field unvisited : unvisitedFields ) {
因为我有时间问题,解决这个问题就足够了,但是如果我使用了错误的做法,我想知道解决这个问题的更好方法是什么。
下面方法的完整代码,unvisitedFields初始化为类变量,但具有与visitedFields相同的参数。它之所以成为类变量,是因为我在类的顶部填充了它,以及一个2D数组
public void calculcateSPath(Field curLocation , Field target ) {
Set<Field> visitedFields = new HashSet<>();
ArrayList<Field> shortestPath = new ArrayList<>();
shortestPath.add( target );
curLocation .setDistance( 0 );
unvisitedFields.remove( curLocation );
visitedFields.add( curLocation );
// until all fields have a corresponding value to field, it continues searching.
while( unvisitedFields.isEmpty() == false ) {
// iterate through the Set containing all unvisited fields.
for( Field unvisited : unvisitedFields ) {
//iterate through the Set containing all visited fields.
for( Field posNeighbor : visitedFields ) {
// if the unvisited field has a visited field as neighbor
if( unvisited.allNeighbors().containsValue( posNeighbor )) {
// check if the wall between them is down
if(( unvisited.getNeighbor( Direction.up ).equals( posNeighbor ) && posNeighbor.drawDown() == false )
|| ( unvisited.getNeighbor( Direction.right ).equals( posNeighbor ) && unvisited.drawRight() == false )
|| ( unvisited.getNeighbor( Direction.down ).equals( posNeighbor ) && unvisited.drawDown() == false )
|| ( unvisited.getNeighbor( Direction.left ).equals( posNeighbor ) && posNeighbor.drawRight() == false )) {
visitedFields.add( posNeighbor );
// if so, check if the current distance is smaller than the previous distance.
if( unvisited.getDistance() > ( posNeighbor.getDistance()+1 ) ) {
// assign the new shorter distance and the connection point
unvisited.setDistance( posNeighbor.getDistance() + 1 );
unvisited.setVisitedNeighbors( 1 );
unvisited.setPrevious( posNeighbor );
}
// if not, add a count to the visited neighbors
} else {
unvisited.setVisitedNeighbors( 1 );
}
//if all neighbors have been visited, remove the field from the unvisited list and add to visited.
if( unvisited.getVisitedNeighbors() == unvisited.allNeighbors().size() ) {
unvisitedFields.remove( unvisited );
visitedFields.add( posNeighbor );
}
}
}
}
}
} // ends calculateSPath()
public void calcultatespath(字段curLocation,字段目标){
Set visitedFields=new HashSet();
ArrayList shortestPath=新的ArrayList();
最短路径。添加(目标);
curLocation.setDistance(0);
未访问的字段。删除(卷曲定位);
visitedFields.add(curLocation);
//直到所有字段都有对应于字段的值,它才继续搜索。
while(unvisitedFields.isEmpty()==false){
//遍历包含所有未访问字段的集合。
对于(未访问的字段:未访问的字段){
//遍历包含所有已访问字段的集合。
用于(字段:已访问字段){
//如果未访问的字段有一个已访问的字段作为邻居
if(unvisited.allneighbor().containsValue(posNeighbor)){
//检查他们之间的墙是否倒了
if((unvisited.getNeighbor(Direction.up).equals(posNeighbor)&&posNeighbor.drawDown()==false)
||(unvisited.getNeighbor(Direction.right).equals(posNeighbor)&&unvisited.drawRight()==false)
||(unvisited.getNeighbor(Direction.down).equals(posNeighbor)&&unvisited.drawDown()==false)
||(unvisited.getNeighbor(Direction.left).equals(posNeighbor)和&posNeighbor.drawRight()==false)){
visitedFields.add(posNeighbor);
//如果是,请检查当前距离是否小于上一距离。
if(unvisited.getDistance()>(posNeighbor.getDistance()+1)){
//指定新的较短距离和连接点
unvisited.setDistance(posNeighbor.getDistance()+1);
未访问。设置访问邻居(1);
未访问。setPrevious(posNeighbor);
}
//如果没有,则向访问的邻居添加计数
}否则{
未访问。设置访问邻居(1);
}
//如果访问了所有邻居,请从未访问列表中删除该字段并添加到已访问。
if(unvisited.getVisitedNeights()==unvisited.allNeights().size()){
未访问字段。删除(未访问);
visitedFields.add(posNeighbor);
}
}
}
}
}
}//结束calculatePath()
在java中使用“for-each”循环时,实际上是在幕后使用迭代器。看
由于您在不使用迭代器的add或remove方法的情况下修改基础集合(remove),因此会得到一个ConcurrentModificationException
,因为java集合很快就会失败:
如果迭代器抛出
以下两种情况下的ConcurrentModificationException
条件:
Collection items = ...
Iterator itr = items.iterator();
while(itr.hasNext()) {
Object o = itr.next();
boolean condition = ...
if(condition) {
itr.remove();
}
}
Collection items = ...
Collection itemsToRemove = ...
for (Object item : items) {
boolean condition = ...
if (condition) {
itemsToRemove.add(item);
}
}
items.removeAll(itemsToRemove);
或者,如果您可以(并且更愿意)在迭代完成后进行修改,您可以这样做:
Collection items = ...
Iterator itr = items.iterator();
while(itr.hasNext()) {
Object o = itr.next();
boolean condition = ...
if(condition) {
itr.remove();
}
}
Collection items = ...
Collection itemsToRemove = ...
for (Object item : items) {
boolean condition = ...
if (condition) {
itemsToRemove.add(item);
}
}
items.removeAll(itemsToRemove);
如果集合的类型为,则可以通过调用。ListIterator通过添加允许双向遍历列表的方法来增强迭代器,并允许通过添加和删除项或替换当前项来修改集合。一般提示:在许多情况下,通过转换pat可以避免ConcurrentModificationException