Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Foreach against for(int...) loop - why does foreach raises exceptions when removing elements? [duplicate]

I was wondering why I cannot remove elements from a list, when I'm iterating it with a foreach-loop like:

List<Object> objects = new ArrayList<Object>();
Object one = new Object();
Object two = new Object();
Object three = new Object(); 

objects.add(one);
objects.add(two);
objects.add(three);

and then removing the elements like:

foreach(Object o : objects){
  objects.remove(three); //I know that o is my current object
}

It seems like the foreach-loop doesn't allow to remove objects, which are "still" in the loop-queue. Am I correct?

And why does the for-int-loop doesn't care about this? In this loop I can easily remove objects, which are still in the loop.

Thanks

like image 474
augmentie123 Avatar asked May 27 '13 23:05

augmentie123


2 Answers

Well, initially the question was tagged C#, now removed. however....

It's not true that a for/loop doesn't care if you remove an element from the collection. If you remove elements while going forward, you will have problem indexing elements after the one you have removed because the index doesn't match anymore your next element. You avoid problems with for/loop only if you loop in reverse order (from the last element to the first)

The foreach suffers internally of the same problem. The enumerator maintains a Current position to the element, if you remove the element and then advance to the Next position, the Current indexer doesn't point to the element after the one removed, but to an element two position after the one removed.

For example:

Suppose a string collection of "birds", "animals", and "fishes"

  • At the foreach start, the internal Current is 0 ( points to "birds")
  • you remove "birds", so "animals" is at index 0 (where Current still points to)
  • You advance to the Next element (Current=1, points to "fishes")
  • Without the exception the Next advance will exit the loop.

foreach has not been designed to allow this scenario.

like image 98
Steve Avatar answered Sep 20 '22 06:09

Steve


As far as Java is concerned, the answer is in the javadoc (emphasis mine):

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.

like image 25
assylias Avatar answered Sep 22 '22 06:09

assylias