6

我有 2 个HashMap<Integer,Point3D>对象名称是positiveCoOrdinate and negativeCoOrdinates.

我正在检查PositiveCoOrdinates以下条件。如果它满足添加到negativeCoOrdinates和删除的对应点positiveCoOrdinates

  HashMap<Integer, Point3d> positiveCoOrdinates=duelList.get(1);
  HashMap<Integer, Point3d> negativecoOrdinates=duelList.get(2);
  //condition
  Set<Integer> set=positiveCoOrdinates.keySet();
    for (Integer pointIndex : set) {
        Point3d coOrdinate=positiveCoOrdinates.get(pointIndex);
        if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) {
            negativecoOrdinates.put(pointIndex, coOrdinate);
            positiveCoOrdinates.remove(pointIndex);
        }
    }

在添加、删除时间时出现以下错误。

 Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at PlaneCoOrdinates.CoordinatesFiltering.Integration(CoordinatesFiltering.java:167)
at PlaneCoOrdinates.CoordinatesFiltering.main(CoordinatesFiltering.java:179)

对于我的测试,我System.out.println(coOrdinate.x);在条件中提到了声明。它If工作正常。

如果我在条件内添加 2 行(我上面提到的)If,它会抛出错误。

我怎样才能解决这个问题。

谢谢。

4

4 回答 4

11

最简单的方法是复制 keySet:

  Set<Integer> set= new HashSet<Integer>(positiveCoOrdinates.keySet());

出现此问题的原因是您正在修改positiveCoOrdinates使用Iterator迭代键的时。

您还可以重构代码并在条目集上使用迭代器。这将是一个更好的方法。

Set<Entry<Integer, Point3d>> entrySet = positiveCoOrdinates.entrySet();

    for (Iterator<Entry<Integer, Point3d>> iterator = entrySet.iterator(); iterator.hasNext();) {
        Entry<Integer, Point3d> entry = iterator.next();
        Point3d coOrdinate = entry.getValue();
        if (coOrdinate.x > xMaxValue || coOrdinate.y > yMaxValue
                || coOrdinate.z > zMaxValue) {
            Integer pointIndex = entry.getKey();
            negativecoOrdinates.put(pointIndex, coOrdinate);
            iterator.remove();
        }
    }
于 2013-10-01T11:05:04.880 回答
2

remove()使用增强for-each循环时,您不能从迭代集合中。for-each循环Iterator<Integer>隐式使用。JavaDoc明确指出

此类的所有“集合视图方法”返回的迭代器都是快速失败的:如果在创建迭代器后的任何时间对映射进行了结构修改,除了通过迭代器自己的remove()方法之外的任何方式,迭代器将抛出一个 ConcurrentModificationException. 因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。

循环在for-each内部创建一个迭代器并使用它来遍历集合。然后你改变集合的结构......并且迭代器必须失败。问题是您无权访问迭代器的方法,因此您必须Iterator<Integer>显式使用。生成的遍历字节码将是相同的,唯一的区别是您可以在遍历列表时从列表中删除元素。

Set<Integer> set = positiveCoOrdinates.keySet();
for (Iterator<Integer> iterator = set.iterator(); iterator.hasNext(); ) {
    Integer pointIndex = iterator.next();
    Point3d coOrdinate = positiveCoOrdinates.get(pointIndex);
    if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) {
        negativecoOrdinates.put(pointIndex, coOrdinate);
        iterator.remove(pointIndex);    // this line changed!
    }
}

如果您不熟悉迭代器及其功能,请参阅关于集合的 Oracle 教程

AnIterator是一个对象,它使您能够遍历集合并在需要时有选择地从集合中删除元素。你可以通过调用它的 方法来获得Iterator一个集合。iterator()

请注意,这Iterator.remove()是在迭代期间修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了基础集合,则行为未指定。

当您需要时使用Iterator而不是构造:for-each

  • 删除当前元素。该for-each构造隐藏了迭代器,因此您不能调用remove(). 因此,该for-each 构造不可用于过滤。
于 2013-10-01T11:12:03.173 回答
0

如果要在运行时修改集合,则需要使用Iterator而不是增强的 for 循环。因为增强的 for 循环只提供只读功能。以下是迭代器示例:

Iterator<Entity> iterator = collection.Iterator();
while(iterator.hasNext()){
  //DO Your Stuff
  iterator.remove(); // this function call remove the element from collection at run time
}
于 2013-10-01T11:11:30.670 回答
0

正如 René 指出的那样,这个非常常见的问题的原因是在另一个集合正在读取该集合的同时对其进行了修改。

您可以使用ConcurrentHashMapCopyOnWriteArrayLit之类的集合,但请注意,这些方法可能有点昂贵,并且在迭代中消除读取同一集合的简单代码更改器将解决此类问题。

于 2013-10-01T11:34:29.690 回答