1

I have a question connected with my GalaxyInvaders clone.

What is the difference between for and foreach iterating through ArrayList?

I'm modifying ArrayLists (changing variables / removing some objects) using foreach loops (I'm blocking sections before doing that using Semaphores).

Question is, when I use foreach statement, application throws exception.

Exception in thread "Thread-39" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at pl.mosek.MyPanel2$ColissionDetector.run(GUI.java:421)
at java.lang.Thread.run(Unknown Source)

When I use classic for statement, problem magically dissapears. Can somebody explain me why is that?

CODE:

@Override
    public void run() {

        while (true) {
            if (ship.getBullets().isEmpty() == false
                    && monsters.isEmpty() == false) {

                semaphoreLock(semaphoreBullet);

                for (Bullet i : ship.getBullets()) {
                    if (i.isDestroyed() != true) {

                        semaphoreLock(semaphoreMonster);

                        for (Enemy j : monsters) {
                            if (i.getBounds()
                                    .intersects(j.getBounds())
                                    &&j.isDestroyed() != true) {
                                i.setDestroyed(true);
                                i.setVisible(false);

                                j.setDestroyed(true);
                                j.setVisible(false);
                            }
                        }
                    }
                    semaphoreRelease(semaphoreMonster);
                }
                semaphoreRelease(semaphoreBullet);

            }
            try {
                Thread.sleep(25);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

If i switch foreach to for statments, everything working correctly.

6
  • 1
    Could you show us the code which produces that exception? Commented Jan 5, 2014 at 20:07
  • In Java iterators (the ArrayList iterator in this case) can not modify the underlying connection. They must change a copy of the collection or iterate over a copy of it - it's part of the abstraction,. Commented Jan 5, 2014 at 20:08
  • Java ConcurrentModificationException Commented Jan 5, 2014 at 20:08
  • @BenjaminGruenbaum That's quite wrong. See Iterator#remove. Commented Jan 5, 2014 at 20:08
  • @MarkoTopolnik fair enough, what I meant was iterating using a for : loop. Removing an element during that is undefined behavior. If you have the actual Iterator you can remove elements. As for the #remove remark - I raise you an UnsupportedOperationException :P Commented Jan 5, 2014 at 20:10

2 Answers 2

3

With a standard for-loop, you access the elements of the list via get() and (perhaps) set them via set(). These methods cannot detect concurrent modification. However, with a for-each loop, you are actually using an Iterator as returned by the list's iterator() method, which does check for concurrent modification. Hence the difference.

A for-each loop

for (Element e : list) {
    ...
}

actually becomes something like:

for (Iterator<Element> iter = list.iterator(); iter.hasNext();) {
    Element e = iter.next();
    ...
}
Sign up to request clarification or add additional context in comments.

7 Comments

So for statement only hiding the problem? Or can I use it normally if it works?
@krzakov It depends; if all you're doing is altering existing elements (without adding/removing), then it should be alright. Where is the exception actually being thrown?
But Iterator does not provide modification on objects. First for throwing me an exception. Notice that I do not remove any objects in this particular part of the code but modifying variables. I still dont know what is whrong with this code, not a single remove operation is performed.
@krzakov The concurrent modification exception is only thrown when the list itself is being modified. Modifying the objects that are contained within the list will have no effect. So somewhere in your loop you are modifying the structure of the list. Note that this can be either a remove, add or set operation.
Thing is I do not modify structure of the list. Maybe another thread doing it but that's why I use semaphores.
|
1

While some existing answers may explain what you can do to make your code functional, they fall short of explaining exactly what's going wrong, and why.

In particular, foreach syntax makes use of an iterator via ArrayList#iterator(), and the docs for ArrayList say:

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

1 Comment

Is it recommended using in similar situations classic for statement?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.