ConcurrentModificationException while iterating through Arraylist (not removing) - java

I currently have a problem with iterating through an ArrayList. I've read several posts here, but nothing seem to have resolved my problem. Here is my code:
//restaurants contains a list of all restaurants and i want to filter them
List<Restaurant> newList = new ArrayList<Restaurant>();
List<Restaurant> allRestaurants = new ArrayList<Restaurant>(restaurants);
if (query != null && query.length() > 0 && !query.equals("*")) {
synchronized (allRestaurants) {
for (Iterator<Restaurant> it = allRestaurants.iterator(); it
.hasNext();) {
Restaurant restaurant = it.next();
if (restaurant.getCity().contains(query)) {
synchronized (newList) {
newList.add(restaurant);
}
} else {
newList = allRestaurants;
}
}
}
This is code was modified by me with several ideas i've read here (synchronized, using iterator instead of for-each-loop). I even have synchronized the whole method and still get an exception.
The exception is happening in following line:
Restaurant restaurant = it.next();
which I don't understand. I am not manipulating the list in this line. Why is this happening and how can i fix it?

else{
newList = allRestaurants;
}
That is almost certainly your issue.
Assigning newList to allRestaurants then adding to newList is causing your comodification.
That is after newList = allRestaurants any add to newList will update the mod count in allRestaurants and thus your error.

In the else branch
else {
newList = allRestaurants;
}
You set newList to be allRestaurants. The next modification newList.add(restaurant); changes the allRestaurants-list.
The exception is thrown when it.next() is called, because then the iterator checks if its source was changed.

The failure starts with:
newList = allRestaurants;
which points both references to the same list (i.e. the one you are iterating over). You then do the following:
newList.add(restaurant);
modifying the list. From the javadoc of ConcurrentModificationException:
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

Your problem is in the else clause.
newList = allRestaurants;
That's why you get exceptions

You can't change the ArrayList that is used for iteration inside a loop; that is what ConcurrentModificationException says (http://docs.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html) and newList = allRestaurants; plus newList.add(restaurant);does potentially change the list allRestaurants.
So what you could do is
create another list
put items to modify in that list
add/remove the new list (addAll or removeAll) to your old one after the loop
Check out http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html for more.

Related

Using only nested loops, if-else statements, and ArrayList methods, how do I locate and remove duplicate values in an ArrayList (Java)? [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here

Iterator inside Iterator ConcurrentModificationException

I am having the following problem:
Given an ArrayList (let's call it list), how can I "double-iterate" through it without getting ConcurrentModificationException?
Here's what I've tried:
iterator out = list.iterator();
iterator in;
while(out.hasNext()){
...
in = list.iterator();
while(in.hasNext()){
...
if(something)
in.remove();
}
You can't do that. A potential solution might be to mark objects to be removed, for example:
final List<Foo> toRemove = new ArrayList<>();
for (Foo a : list)
{
for (Foo b : list)
{
if (something)
{
toRemove.add(b);
}
}
}
list.removeAll(toRemove);
You may need some additional checks to see that the object isn't already marked for removal. It's impossible to say given how vague your example is.
You are trying to modify an iterator. It will give you concurrentModification exception.
In java 8 you can easily remove it using
list.removeIf(someCondition)
Try this link java8 collections
The Iterator instance provided through a call to List#iterator method preserves a count scalar allowing to detect external changes to the Collection container.
When an element is removed from the collection by any other mean than going through the same Iterator#remove(T) call, the count is not updated behind the scenes.
Therefore when you request for the #next() element through the iterator instance, the count is checked against an expected value and if both values does not match (since an element has been removed through another iterator) a ConcurrentModificationException is thrown (even though you may be working in a single threaded environment).
The solution whould be, as #Michael stated, to keep track of the container elements that should be removed then perform a bulk delete:
Collection<Object> temp = new ArrayList<>();
iterator out = list.iterator();
iterator in;
while (out.hasNext()) {
// ...
in = list.iterator();
while (in.hasNext()) {
// ...
if(something)
// just mark the element for deletion
temp.add(in.next());
}
}
// delete all the obsolete elements
list.removeAll(temp);
In collection once iterator creator If you try to modify the content not through same iterator it will throw concurrent exception.If you required some special kind of iterator then you can go ahead and implement your own.

Old for-each loop works, new for-each loop gets ConcurrentModificationException

From what I've read I understand that you get a ConcurrentModificationException when you try to edit a list while it's still being iterated.
Now what I don't get is, why does the old foreach loop not give the exception while the the new foreach loop does?
public void newForeachLoop() {
for (Person person : list) {
if (person.getPosition().equals(this.getPosition())) {
list.remove(person);
}
}
}
public void oldForeachLoop() {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getPosition().equals(this.getPosition())) {
list.remove(list.get(i));
}
}
}
In the old loop you're not using the lists iterator instead you're using a count of the objects in the list.
In the new loop you're using the built-in iterator which is a pointer for that instance. When you remove an item from the list you're modifying that instance and resetting the iterator thus throwing the exception.
Because for each loop is iterator based, you can't just remove an element from the list while iterating over it.
You can even try explicitly using iterator and removing an element.
List<String> list= new ArrayList <String>;
list.add("One");
list.add("two");
list.add("three");
Iterator listItr = list.iterator () ;
while ( listItr.hasNext() )
{
String countStr = itr.next();
if ( countStr.equals ("two"))
itr.remove(); //will not throw any exception
//if you do it list.remove (countStr) //will throw exception
}
Removing an element from list using index while iterating over it, will definitely not throw any exception but you need to be extra careful about its length getting modified. Even indexes of further elements are also disturbed by your operation. So if you take care of this its not a problem.
As #SacJn explained, you cannot make structural changes in the List (e.g. add or remove elements) while iterating it via iterator(). The iterator() will detect the inconsistency and throw a ConcurrentModificationException. In Java-8 there's clean and safe way to solve your task:
public void java8Solution() {
list.removeIf(person -> person.getPosition().equals(this.getPosition()));
}

How to avoid ConcurrentModificationException while iterating this collection?

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.
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);
This code cannot lead to ConcurrentModificationException because after you add an element you break the loop and dont use iterator anymore
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
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;
}
}
Don't use for each, use the good old
for(int i=0; i<collection.size();i++)

getting rid of concurrent modification exception

i have a small problem in java. I am trying to loop through an ArrayList and add more items to the same arraylist during the looping and am getting concurrentModificationexception. what are the work-around for this problem, my code is like this
ArrayList "Errors" is already populated.
ArrayList<MainErrorObject> errors;
ArrayList<MainErrorObject> newList;
for (MainErrorObject current : errors)
{
newList = processErrorObjects(current);
errors.addall(newList);
}
When i try to execute the code above, i get the concurrentmodification exception. please help me in resolving this.
Thanks in advance.
you can't iterate & modify the same collection. So have a temporary ArrayList and copy the content to main list when iteration is done.
ArrayList<MainErrorObject> tempErrors;
for (meObject : Errors) {
newList = processErrorObjects();
tempErrors.addAll(newList);
}
errors.addAll(tempErrors);
Ps: follow the java naming conventions
You can use the Iterator class and use the add() method from Iterator, like this:
ListIterator<MainErrorObject> it = Errors.listIterator();
MainErrorObject me = null;
while(it.hasNext()) {
me = it.next();
if (//condition)
it.add(item);
}
which will never throw such an exception because it's smart enough to handle said concurrent modifications.
Source: ListIterator javadocs
Use ListIterator.
To avoid java.util.ConcurrentModificationException exception, we can add an item through the iterator of list
for (ListIterator<MainErrorObject> itr = Errors.listIterator(); itr.hasNext();) {
newList = processErrorObjects(itr.next());
for (MainErrorObject obj : newList) {
itr.add(obj);
}
}

Categories