0

I was trying to delete a row of JavaFX GridPane with JavaFX Rectangles and I found no way to do so but copying the squares above to one row below. Here is my code to do that but it keeps throwing ConcurrentModificationAcception.

static void copyAbove(int rowToBeDisappear, GridPane mainGrid) {
        for (int y = (rowToBeDisappear-1); 0 <= y ; y--) {
            for (int x = 0; x <= 9; x++) {
                Iterator<Node> iterator = mainGrid.getChildren().iterator();
                while (iterator.hasNext()) {
                    Node sqr = iterator.next();
                    if (sqr == getSqrByIndex(x,y,mainGrid)) {
                        iterator.remove();
                        mainGrid.add(sqr,x,(y+1));
                    }
                }
            }
        }
    }

The error

Caused by: java.util.ConcurrentModificationException at com.sun.javafx.collections.VetoableListDecorator$VetoableIteratorDecorator.checkForComodification(VetoableListDecorator.java:714) at com.sun.javafx.collections.VetoableListDecorator$VetoableIteratorDecorator.hasNext(VetoableListDecorator.java:682) at Main.copyAbove(Main.java:%local_code_row_nvm_this%)

Akmenah
  • 31
  • 8
  • `iterator` of nonconcurrent collection has `fail-fast` mechanism (like `for-each`). – kozmo Jul 28 '20 at 04:46
  • Use the `ListIterator` which allows you to add during iteration (via the Iterator) – Felix Jul 28 '20 at 06:57
  • this smells strongly like an x-y-problem (_trying to delete a row of GridPane_), from your sparce description it looks like just removing all nodes in a given row should do what you need. Please provide a [mcve] of what you __really__ are trying to achieve and what exactly isn't working as expected. – kleopatra Jul 28 '20 at 10:23

2 Answers2

3

Thanks to @Slaw for pointing out the flaw in my solution.

You can't iterate an iterator and modify its backing collection (except through that iterator's remove method) at the same time. Store any structural changes you'd like done on the collection to a temporary collection, then perform them after iterating.

If getSqrByIndex() is guaranteed to return at most one Node given an x and a y, then the following code will not cause CMEs:

Node node = null;

Iterator<Node> iterator = mainGrid.getChildren().iterator();
while (iterator.hasNext()) {
    Node sqr = iterator.next();
    if (sqr == getSqrByIndex(x,y,mainGrid)) {
        node = sqr;
    }
}

if (node != null) {
    mainGrid.getChildren().remove(node);
    mainGrid.add(node, x, y + 1);
}

No Ordinary Love
  • 569
  • 1
  • 4
  • 15
0

I’m a total idiot and new to this so this may be wrong, but why not use a for() loop instead of while()? I believe it keeps it in scope so that you can call iterater.remove(). Also, it may be throwing that because you’re adding objects into your iterator at the same time that you’re iterating. I would try separating the points in which you add and remove objects.

  • 2
    The type of loop does not matter in this case. The problem is modifying the iterator's source in ways other than `Iterator#remove()`. – Slaw Jul 28 '20 at 05:49