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.

krzakov
  • 3,871
  • 11
  • 37
  • 52

2 Answers2

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();
    ...
}
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • So `for` statement only hiding the problem? Or can I use it normally if it works? – krzakov Jan 05 '14 at 20:27
  • @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? – arshajii Jan 05 '14 at 20:36
  • 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 Jan 05 '14 at 20:42
  • @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. – arshajii Jan 05 '14 at 20:45
  • Thing is **I do not** modify structure of the list. Maybe another thread doing it but that's why I use semaphores. – krzakov Jan 05 '14 at 20:50
  • You had right, I found adding function.I missed it. I'm terribly sorry. – krzakov Jan 05 '14 at 20:59
  • @krzakov No problem at all; glad I could help. – arshajii Jan 05 '14 at 20:59
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.

Community
  • 1
  • 1
Mark Elliot
  • 75,278
  • 22
  • 140
  • 160