6

I need to iterate over a collection of items & sometimes add to that collection at the same time. However, incase I add while iterating then I just start the iteration from fresh by breaking out of iteration loop & restarting iteration from beginning. However this leads to ConcurrentModificationException. [code below]

    List<Integer> collection = new ArrayList<>();
    for (Integer lobId: collection) {
         ..
         if (someCondition) {
             collection.add(something); 
             break; 
         }
    }

How could I possibly do something like above avoiding ConcurrentModificationException?

Would it be correct to simply use an Array instead of ArrayList to avoid this exception ? Is there any type of specialized collection for this ?

--

Edit:

I dont want to create a new copy for this arraylist because I'm repeating this entire iteration process multiple times unless some requirement is completed. Creating a new copy each time would bring in some extra overhead, which I would like to avoid if somehow possible.

Also if possible I would like to maintain a sorted order & unique values in that collection. Is there anything that is ready to use in any library? Otherwise I could sort it at the end of iteration process & remove duplicates. That will also do fine for me.

Rajat Gupta
  • 25,853
  • 63
  • 179
  • 294
  • 2
    see http://stackoverflow.com/questions/9806421/concurrentmodificationexception-when-adding-inside-a-for-each-loop-in-arraylist – Vadim Feb 02 '14 at 07:18
  • @user01 modified my response to suit your new requirements – jax Feb 02 '14 at 07:26

5 Answers5

4

Use another collection for the additions and combine them at the end.

List<Integer> collection = new ArrayList<>();
collection.add(...)
...
List<Integer> tempCollection = new ArrayList<>();    
for (Integer lobId: collection ) {
     ..
     if (someCondition) {
         tempCollection.add(something); 
         break; 
     }
}

collection.addAll(tempCollection);
jax
  • 37,735
  • 57
  • 182
  • 278
  • The interface documentation of iterator can be found at http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html Knowing it is part of any basic java certificate. Dublicating the list is not only bad practise, it also leads to major security flaws. – Hannes Feb 02 '14 at 08:00
  • @Hannes I'm not duplicating the list – jax Feb 02 '14 at 08:01
3

This code cannot lead to ConcurrentModificationException because after you add an element you break the loop and dont use iterator anymore

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • But actually it does. But wait.. May be I just simplified it while putting here. It also contained a call to `addAll()` method while iteration.!? – Rajat Gupta Feb 02 '14 at 07:25
  • 1
    You removed your answer about listIterator while I was exploring that option, doesn't that hold good ? – Rajat Gupta Feb 02 '14 at 07:26
  • ListIterator.add will actually insert an element at currrent index and it's probably what you dont want – Evgeniy Dorofeev Feb 02 '14 at 07:32
  • `"This code cannot lead to ConcurrentModificationException.. "`- yeah I investigated about this & found that I wasn't `break`-ing when doing `.addAll(EMPTY_LIST)` in which case it was leading to `ConcurrentModificationException` – Rajat Gupta Feb 03 '14 at 11:33
2

ConcurrentModificationException basically means that you're iterating over a Collection with one iterator (albeit implicitly defined by your enhanced for loop) and invalidating it on the fly by changing the Collection itself. You can avoid this by doing the modifications via the sameiterator:

List<Integer> collection = new ArrayList<>();
ListIterator<Integer> iter = collection.listIterator();
while (iter.hasNext()) {
     Integer currVal = iter.next();
     if (someCondition) {
         iter.add(something); // Note the addition is done on iter
         break; 
     }
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • Since when does Iterator have an add method? Only ListIterator has an add method. Change your Iterator in ListIterator and this answer is correct. Since user01 stated he has a List, this will work. If he's using another Collection, then it won't work. – Olivier Grégoire Feb 02 '14 at 11:48
  • @ogregoire indeed, you are correct. Wasn't paying attention. Fixed accordingly - thanks for noticing! – Mureinik Feb 02 '14 at 11:53
2

if I understand you right, you want to iterate over the list , if some condition , you want to break the iteration , and an item and start fresh .

In the case do this:

   List<Integer> collection = new ArrayList<>();
   boolean flag = false;
   Integer item = 
    for (Integer lobId: collection) {
         ..
         if (someCondition) {
             flag = true;
             item = something; 
             break; 
         }
    }

   if (flag){
      collection.add(item);
   }

if someone else is going to change the list outside out loop - you will need to sync those access - read iterator thread safe , and use the other answers here like copying the list or some other copy on write

Community
  • 1
  • 1
Mzf
  • 5,210
  • 2
  • 24
  • 37
-1

Don't use for each, use the good old

for(int i=0; i<collection.size();i++)
Camilo
  • 1,889
  • 2
  • 17
  • 16
  • It doesn't answer his question. – Martin Tuskevicius Feb 02 '14 at 07:40
  • you mean this question? 'How could I possibly do something like above avoiding ConcurrentModificationException?' – Camilo Feb 02 '14 at 07:43
  • Yes. He asked about iterating a `Collection` whilst also adding and removing elements sometimes. A standard for-loop would not even work in this case as variable `i` implies that you are retrieving based on an index (like within a list), and not all collections necessarily support that (consider a `Set`). Furthermore, adding or removing an element while iterating using said loop would throw a `ConcurrentModificationException` in most cases, which creates the problem that he was asking about in the first place. – Martin Tuskevicius Feb 02 '14 at 07:47
  • 1
    1. ok, my bad, i assumed he/she was iterating over a list, must have been because he explicitly states that he's iterating over an arrayList, and 2. no, in this case, you get a ConcurrentModificationException because the foreach loop uses the iterator of the list, and being an arrayList, it's a fail-fast one, with my answer you don't get to use the iterator so you don't get the exception – Camilo Feb 02 '14 at 08:03
  • and 3. it's not nice to modify an arrayList inside a loop like this, but then again, he explicitly states that after modifying the list, he breaks the loop, so it does no harm. I think this and @Mureinick are the best answers so far, some people should try reading before clicking. – Camilo Feb 02 '14 at 08:09
  • Your answer is pretty incomplete, but the OP is indeed **appending** items to an **ArrayList**. So the `Listterator` solutions does something different. @MartinTuskevicius: The calls his variable `collection`, but initializes it as an `ArrayList`. Anyway, this answer is more correct than using `ListIterator` as it maintains the list order. – maaartinus Feb 02 '14 at 17:03
  • When the collection is an ArrayList, a for loop based on the index can work. Adding elements at the end of the list won't cause problems. If you remove an element at or before position i, decrement i by 1 so the iteration won't skip any elements. – Jared Levy Feb 06 '14 at 06:50