26

I want to avoid getting ConcurrentModificationException. How would I do it?

3

5 Answers 5

55

You may use a ListIterator which has support for a remove/add method during the iteration itself.

ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
    if(iter.next().getIsbn().equals(isbn)){
        iter.add(new Book(...));
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Interesting, I didn't know about this class. This differs from JimN's solution in that it will insert inline rather than add to the end. While I'm not sure that's what the OP asked for (although there is ambiguity now that I've looked again), I'm giving you a +1 as it does achieve the elements being added to the list.
12

Instead of using an iterator, you can use a for loop with an index. For example:

int originalLength = list.length();
for (int i = 0; i < originalLength; i++) {
  MyType mt = list.get(i);
  //... processing
  //... insertions
}

4 Comments

+1 for the best solution for the add(T) operation, which is what was asked for.
With the only evident problem that if the list implementation does not provide random access (i.e. LinkedList), you'd have to pay the performance penalty. For instance, in a LinkedList, every time you do a get(i) you will have to visit all the nodes until you reach the node i. Not a good approach IMHO.
@JimN you are creating burden to the jvm by visiting each and every index, its not a good approach
@Edwin While that's a fair point if the user is using a LinkedList, the question does have the arraylist tag.
6

You want to use a ListIterator. You can get one of these from any kind of list, though for efficiency you probably want to get one from a LinkedList.

import java.util.*;
class TestListIterator {
  public static void main(String[]args) {
    List<Integer> L = new LinkedList<Integer>();
    L.add(0);
    L.add(1);
    L.add(2);
    for (ListIterator<Integer> i = L.listIterator(); i.hasNext(); ) {
      int x = i.next();
      i.add(x + 10);
    }
    System.out.println(L);
  }
}

Prints [0, 10, 1, 11, 2, 12].

Comments

2

Create a new list, and populate that one.

List<MyType> originalList = ...
List<MyType> newList = new ArrayList<>(originalList);

for(MyType type : originalList)
{
  // Some decisions
  newList.add(new MyType());
}

3 Comments

Isn't there anything more practical? This will be a repeated operation, I want to avoid copying so much. Or should I just use a temporary list for the new objects and merge the 2 lists at the end?
originalList.addAll( newList ); should be added.
@stacker If you read the code again, you'll find that will cause duplicates. If you want to store it in the first list, you would do originalList = newList;. That doesn't particularly matter though, as JimN's solution is better for the add(T) operation.
2

There are three approaches to avoid above exception

  1. You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.

  2. You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.

  3. If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. It is the recommended approach.

3 Comments

I do have a synchronized block, but the problem persists:synchronized (ballsLocal) { initialSize = ballsLocal.size(); for (int i = 0; i < initialSize-1; i++) { etc...
synchronized only protects against other threads; if he's iterating and inserting from the same thread, then #2 doesn't help. Ditto for #3.
I do not see how synchronization will prevent the ConcurrentModificationException. This exception happens in single-threaded code. Am I missing something?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.