-1

I had some trouble using a for each loop for an List at my android project. The error is made by an iterator (or I should better say "the error is made by me - not knowing how to use the iterator"^^). The List is looped through in order to draw bullet objects on a canvas. When one of the bullets leaves the screen I delete this object.

Using a "normal" for-loop solved the error:

for (int ii = 0; ii < bulletList_P1.size(); ii++)
                bulletList_P1.get(ii).draw(canvas);

this implementation brings errors:

for (Bullet bullet : bulletList_P1)
                bullet.draw(canvas);

I found THIS here on stackoverflow. The difference to my problem is that in this case new objects are created - my question is now how to deal with this situation when objects get removed (deleted from list).

How massive will be the difference of performance using one or the other implementation?

Community
  • 1
  • 1
Martin Pfeffer
  • 12,471
  • 9
  • 59
  • 68
  • 3
    The problem is actually exactly the same. You can't structurally modify a collection while you are iterating over it with a for-each loop. Period. As long as you aren't using a `LinkedList`, the performance is likely to be the same. I would also like to point out that your "normal" for loop has the potential to skip elements. In addition, where do you remove the bullet? In `draw()`? – awksp Jun 19 '14 at 07:11
  • You can remove elements in a `for-each` loop using an `iterator`. This question has been already answered http://stackoverflow.com/questions/6958478/modifying-a-collection-while-iterating-using-for-each-loop – Raul Rene Jun 19 '14 at 07:14
  • 1
    Read [ForLoopWorking](http://stackoverflow.com/questions/19511956/java-for-each-loop-working) to better understand how to handle remove scenario as mentioned at last section in question..... – Deepak Bhatia Jun 19 '14 at 07:14
  • @RaulRene That will still cause a `ConcurrentModificationException`, because the for-each loop produces its own iterator. You have to use a `while` loop or a regular `for` loop. – awksp Jun 19 '14 at 07:16
  • "*this implementation brings errors*" > **This is not a sufficient problem description.** Yes, people are probably guessing your error correctly, but you should be telling us so we don't need to guess. You also don't show us any code that triggers an error. – Duncan Jones Jun 19 '14 at 07:23
  • Thanks a lot. I read this [link](http://stackoverflow.com/questions/21446414/why-are-some-iterators-faster-than-others-in-c) too. Very interesting topic... – Martin Pfeffer Jun 19 '14 at 07:24
  • @Duncan did you read my problem description completely? – Martin Pfeffer Jun 19 '14 at 07:28
  • 1
    @MartinPfeffer Yes. There is just enough information there for people to figure out your issue, but you should be clearer about the error you get. Reading "*I found [THIS](http://stackoverflow.com/questions/6866238/concurrent-modification-exception-adding-to-an-arraylist) here on stackoverflow*" is not as helpful as "*I get a `ConcurrentModificationException` here is my stack trace*". You've also shown us code samples, but neither includes enough detail to reproduce the problem. – Duncan Jones Jun 19 '14 at 07:31
  • Okay, maybe your right. I cleared my Logcat hours ago - so I wasn't able to tell the error exactly. Just a minute ago I remember that the error was told in the link I posted, too. Next time I will be more exact with my error description. ;) – Martin Pfeffer Jun 19 '14 at 07:38

1 Answers1

1

You cannot typically modify a Collection while you are iterating over it. Strategies around this typically fall into:

i. Copy/Clone the original collection purely to iterate over it, while you change the original collection.

for (Bullet bullet : new ArrayList<Bullet>(bulletList_P1))
    bullet.draw(canvas);

(or even better yet, use the Guava library's ImmutableList.copyOf method)

ii. Collect up your mutations during the iteration and have a separate phase to apply the mutations. For your example, you might create a set of bullets that have left the screen during the draw phase. Then use a removeAll to remove the errant bullets at the end.

ArrayList<Bullet> removals = new ArrayList<Bullet>();
for (Bullet bullet : bulletList_P1)
    if (!bullet.draw(canvas))
        removals.add(bullet);
bulletList_P1.removeAll(removals);

iii. Use an iterator and use the remove method of the iterator to modify the collection as you iterate over it.

for (Iterator<Bullet> iterator = bulletList_P1.iterator(); iterator.hasNext(); ) {
    Bullet bullet = iterator.next();
    if (!bullet.draw(canvas))
        iterator.remove();
}
Oli
  • 597
  • 4
  • 5
  • I took your first solution (my code is already very overloaded) and the smallest code is the most likely (at the moment).. Thank you very much, works perfectly. – Martin Pfeffer Jun 19 '14 at 07:46