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%)

3
  • iterator of nonconcurrent collection has fail-fast mechanism (like for-each). Commented Jul 28, 2020 at 4:46
  • Use the ListIterator which allows you to add during iteration (via the Iterator) Commented Jul 28, 2020 at 6: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 minimal reproducible example of what you really are trying to achieve and what exactly isn't working as expected. Commented Jul 28, 2020 at 10:23

2 Answers 2

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);
}

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this worked...
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.

1 Comment

The type of loop does not matter in this case. The problem is modifying the iterator's source in ways other than Iterator#remove().

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.