需要帮助根据比较值修改列表(并发修改)

Need help modifying list based on comparison values (ConcurrentModification)

我正在尝试通过点及其距离的排列来了解某些东西(不要告诉我没有,这是我失败的项目)的可能性。

for (Point p1 : results) {
    remove.clear();
    for (Point p2 : results) {
        if (Math.sqrt(
            Math.pow(p1.getX() - p2.getX(), 2)
            + Math.pow(p1.getY() - p2.getY(), 2)
        ) % 1 > 0) {
            results.remove(p2);
        }
    }
}

基本上,我正在尝试检查两个点是否具有整数距离,如果不是,则将其从集合中删除,并对所有点(剩余)执行此操作。

但是,我得到了一个 ConcurrentModificationException,但我不确定如何重构它来完成相同的任务,而不只是以另一种方式引发错误。

是否有任何解决方法,或者它只是 Java 的限制?

编辑:虽然重复建议 link 提供了洞察力,但答案对单个循环的关注有一些不适用的多余部分。如果这个问题是重复的,前提是使用 Iterator 就是答案。

你可以这样做:

Iterator<Point> iterator = results.iterator();
while (iterator.hasNext()) {
  Point p1 = iterator.next();
  boolean shouldBeRemoved = false;
  for(Point p2 : results) {
    if (p2 != p1 && (Math.sqrt(Math.pow(p1.getX() - p2.getX(), 2)
                             + Math.pow(p1.getY() - p2.getY(), 2))
                     % 1 > 0)) {
      shouldBeRemoved = true;
      break;
    }
  }
  if (shouldBeRemoved) {
    iterator.remove();
  }
}

不同之处在于显然 p1 而不是 p2 被删除,但是因为我们在这里处理 Set...

remove it from the set

...顺序并不重要,对吧?

这似乎是因为您正试图删除相同的 Point 结构。考虑第一点的情况。 p1 和 p2 均指结果中的第一个点。 p1 和 p2 之间的距离为零,因为它们指向同一点。然后你试图删除 p2 这实际上是 p1 本身。请参阅 link http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html 了解更多关于为什么即使在一个线程试图访问和修改某些结构的情况下也会出现此异常的原因。

您可以像下面这样修改上面的代码:-

boolean[] if_deleted = new boolean[results.size()];

for (int i = 0; i < results.size(); ++i) {
    if_deleted[i] = false;
}

for (int i = 0; i < results.size(); ++i){
    for(int j = i + 1; j < results.size(); ++j)
            Point p1 = (Point)results.get(i);
            Point p2 = (Point)results.get(j);
            if (!if_deleted[i] && !if_deleted[j]) { 
                if (Math.sqrt(
                    Math.pow(p1.getX() - p2.getX(), 2)
                            +
                            Math.pow(p1.getY() - p2.getY(), 2))
                    % 1 > 0){
                        if_deleted[j] = true;
                        results.remove(p2);
                }
            }    
    }
}

for (int i = 0; i < results.size(); ++i) {
    if (if_deleted[i]) {
        results.remove(i);
    }
}

一些 Collection 实现使用“fail-fast”迭代器。直接从 Collection 中删除一个项目(使用 Collection#remove)并迭代它会导致该异常。

增强的 for 循环使用集合的迭代器遍历集合。

您可以将增强循环更改为常规 for 循环:

for(int i = 0; i < results.size(); i++) {
    for(int j = 0; j < results.size(); j++) {
    Point result = results.get(j);
        if(...) {
            //results.remove(j); or
            //results.remove(result);
        }
    }
}

如评论中所述,这不适用于 Set。在这种情况下,您可以简单地保留对集合迭代器的引用,并使用它来删除项目:

Iterator<Point> firstIter = results.iterator();
while(firstIter.hasNext()) {
    Point p1 = iterator.next();

    Iterator<Point> secondIter = results.iterator();
    while(secondIter.hasNext()) {
        Point p2 = secondIter.next();

        if(...) {
            secondIter.remove();
        }
    }
}

我重构为

    for (int p1 = 0;  p1 < results.size() ; p1++){
        for (int p2 = p1;  p2 < results.size() ; p2++){
                if (Math.sqrt(
                        Math.pow(results.get(p1).getX() - results.get(p2).getX(), 2)
                            +
                        Math.pow(results.get(p1).getY() - results.get(p2).getY(), 2))
                        % 1 > 0){
                            results.remove(p2);
                            p2--;
                }
        }
    }

但我不确定它是否像我预期的那样工作。