This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 2 years ago.
I have this little piece of code and it gives me the concurrent modification exception. I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
List<String> s = new ArrayList<>();
ListIterator<String> it = s.listIterator();
for (String a : args)
s.add(a);
if (it.hasNext())
String item = it.next();
System.out.println(s);
}
}
To avoid the ConcurrentModificationException, you should write your code like this:
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
List<String> s = new ArrayList<String>();
for(String a : args)
s.add(a);
ListIterator<String> it = s.listIterator();
if(it.hasNext()) {
String item = it.next();
}
System.out.println(s);
}
}
A java.util.ListIterator allows you to modify a list during iteration, but not between creating it and using it.
I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.
Between creating the iterator and starting to use the iterator, you added arguments to the list that is to be iterated. This is a concurrent modification.
ListIterator<String> it = s.listIterator();
for (String a : args)
s.add(a); // concurrent modification here
if (it.hasNext())
String item = it.next(); // exception thrown here
Create the iterator AFTER you've finished adding elements to the list:
for (String a : args)
s.add(a);
ListIterator<String> it = s.listIterator();
if (it.hasNext())
String item = it.next();
From the JavaDoc: for ConcurrentModificatoinException: "it is not generally permssible for one thread to modify a Collection while another thread is iterating over it".
It simply means that if you still have an open iterator, you aren't allowed to modify the list because the iterator loop will break. Try moving ListIterator<String> it = s.listIterator(); till after the for loop.
You are not allowed to continue iterating over an iterator after the underlying list is modified. Here you create the iterator before adding a few items to s, and then proceed to do a hasNext() and a next() on it after the additions, leading to the ConcurrentModificationException
If the above solutions doesn't work properly. You can use old for-loop for iterating a List at the same time adding new items. See the example below:
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
ArrayList<AClass> aList = new ArrayList<AClass>(); // we will iterate this
// this will cause ConcurrentModificationException.
// Since we are iterating the list, at the same time modifying it.
/*for(AClass a: aList){
aList.add(someMethod(a));
}*/
// old fashion for-loop will help
int limit = aList.size();
for(int i=0; ctr<limit; ++i){
AClass a = aList.get(i);
aList.add(someMethod(a));
}
}
}
to understand this lets look at source of HashMap implementation:
public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{
which contains HashIterator as below:
private abstract class HashIterator {
...
int expectedModCount = modCount;
...
HashMapEntry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
....
}
every time you create a iterator:
a counter expectedModCount is created and is set to value of modCount as entry checkpoint
modCount is incremented in cases of use put/get (add/remove)
nextEntry method of iterator is checking this value with current modCount if they are different concurrent modification exception is throw
to avoid this u can:
convert map to an array (not recommended for large maps)
use concurrency map or list classes (CopyOnWriteArrayList / ConcurrentMap)
lock map (this approach removes benefits of multithreading)
this will allow you to iterate and add or remove elements at the same time without rising an exception
Concurrency map/list iterator is a "weakly consistent" iterator that will
never throw ConcurrentModificationException, and guarantees to
traverse elements as they existed upon construction of the iterator,
and may (but is not guaranteed to) reflect any modifications
subsequent to construction.
More info on CopyOnWriteArrayList
ConcurrentModificationException may arise in both single threaded environment and multi-threaded environment.
The main catch is that all the general purpose iterators (like the one used in ArrayList) are all FailFast iterators, which fails when we try to modify one list if one iterator is already iterating over it.
Solution - > Use CopyOnWriteArrayList if such scenario is needed by the requirement rather than using ArrayList.
For a complete demo for this, below mentioned code can be used.
We just need to change the implementation from CopyOnWriteArrayList to ArrayList.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* #author narif
*
*/
public class TestApp {
/**
* #param args
*/
public static void main(String[] args) {
List<String> testList = new ArrayList<>();
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add(6, "abcAtindex6");
int size = testList.size();
System.out.println("The Current List (ArrayList) is: " + testList);
System.out.println("The size of the List (ArrayList) is: " + size);
/* Comment the below lines to get the ConcurrentModificationException */
testList = new CopyOnWriteArrayList<>(testList);
for (String value : testList) {
System.out.println("The Value from ForEach Loop is: " + value);
/*
* Concurrent modification is happening here
* One iterator is iterating over the list while we are trying to add new values to
* the list so the results of the iteration are undefined under these circumstances.
* So teh fail fast iterators will fail and will throw the ConcurrentModificationException.
*/
testList.add("valueFromForLoop");
testList.add("anotherValueFromForEachLoop");
}
Iterator<String> it = testList.iterator();
while (it.hasNext()) {
String abc = it.next();
System.out.println(abc);
testList.add("Value from Iterator1");
testList.add("Value from Iterator2");
testList.add("Value from Iterator3");
testList.add("Value from Iterator4");
}
System.out.println("Did the modificationa and all after conevrting the ArrayList to CopyOnWriteArrayList.");
System.out.println("Calling the method to get the new List..");
testList = new CopyOnWriteArrayList<>(getTheList(testList));
for (String value : testList) {
System.out.println("The value returned from method is : " + value);
}
}
private static List<String> getTheList(List<String> pList) {
List<String> list = new CopyOnWriteArrayList<>(pList);
int i = 0;
for (String lValue : list) {
System.out.println("The list Passed is " + list);
i++;
list.add("localVaueFromMethod" + i);
list.removeAll(pList);
}
return list;
}
}
For more inifo follow this link this may be helpful alot ConcurrentModificationException Java Docs
This didn't work:
LinkedList<String> linkedList = new LinkedList<String>();
ListIterator listIterator = linkedList.listIterator();
linkedList.add("aa");
linkedList.add("bb");
This worked:
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("aa");
linkedList.add("bb");
ListIterator listIterator = linkedList.listIterator();
Have a look at oracle documentation page.
public class ConcurrentModificationException
extends RuntimeException
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible
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.
In your case, you have modified the collection after creating the iterator and hence you have encountered the exception.
If you change your code as per Stephen C answer, you won't get this error.
Related
Note: I am aware of the Iterator#remove() method.
In the following code sample, I don't understand why the List.remove in main method throws ConcurrentModificationException, but not in the remove method.
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer toRemove) {
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer toRemove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
}
Here's why:
As it is says in the Javadoc:
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.
This check is done in the next() method of the iterator (as you can see by the stacktrace). But we will reach the next() method only if hasNext() delivered true, which is what is called by the for each to check if the boundary is met. In your remove method, when hasNext() checks if it needs to return another element, it will see that it returned two elements, and now after one element was removed the list only contains two elements. So all is peachy and we are done with iterating. The check for concurrent modifications does not occur, as this is done in the next() method which is never called.
Next we get to the second loop. After we remove the second number the hasNext method will check again if can return more values. It has returned two values already, but the list now only contains one. But the code here is:
public boolean hasNext() {
return cursor != size();
}
1 != 2, so we continue to the next() method, which now realizes that someone has been messing with the list and fires the exception.
Hope that clears your question up.
Summary
List.remove() will not throw ConcurrentModificationException when it removes the second last element from the list.
One way to handle it it to remove something from a copy of a Collection (not Collection itself), if applicable. Clone the original collection it to make a copy via a Constructor.
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For your specific case, first off, i don't think final is a way to go considering you intend to modify the list past declaration
private static final List<Integer> integerList;
Also consider modifying a copy instead of the original list.
List<Integer> copy = new ArrayList<Integer>(integerList);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
copy.remove(integer);
}
}
The forward/iterator method does not work when removing items. You can remove the element without error, but you will get a runtime error when you try to access removed items. You can't use the iterator because as pushy shows it will cause a ConcurrentModificationException, so use a regular for loop instead, but step backwards through it.
List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
int size= integerList.size();
//Item to remove
Integer remove = Integer.valueOf(3);
A solution:
Traverse the array in reverse order if you are going to remove a list element. Simply by going backwards through the list you avoid visiting an item that has been removed, which removes the exception.
//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
if (integerList.get(i).equals(remove) ) {
integerList.remove(i);
}
}
This snippet will always throw a ConcurrentModificationException.
The rule is "You may not modify (add or remove elements from the list) while iterating over it using an Iterator (which happens when you use a for-each loop)".
JavaDocs:
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.
Hence if you want to modify the list (or any collection in general), use iterator, because then it is aware of the modifications and hence those will be handled properly.
Hope this helps.
I had that same problem but in case that I was adding en element into iterated list.
I made it this way
public static void remove(Integer remove) {
for(int i=0; i<integerList.size(); i++) {
//here is maybe fine to deal with integerList.get(i)==null
if(integerList.get(i).equals(remove)) {
integerList.remove(i);
}
}
}
Now everything goes fine because you don't create any iterator over your list, you iterate over it "manually". And condition i < integerList.size() will never fool you because when you remove/add something into List size of the List decrement/increment..
Hope it helps, for me that was solution.
If you use copy-on-write collections it will work; however when you use list.iterator(), the returned Iterator will always reference the collection of elements as it was when ( as below )
list.iterator() was called, even if another thread modifies the collection. Any
mutating methods called on a copy-on-write–based Iterator or ListIterator
(such as add, set, or remove) will throw an UnsupportedOperationException.
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new CopyOnWriteArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
This runs fine on Java 1.6
~ % javac RemoveListElementDemo.java
~ % java RemoveListElementDemo
~ % cat RemoveListElementDemo.java
import java.util.*;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
~ %
In my case I did it like this:
int cursor = 0;
do {
if (integer.equals(remove))
integerList.remove(cursor);
else cursor++;
} while (cursor != integerList.size());
Change Iterator for each into for loop to solve.
And the Reason is:
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.
--Referred Java Docs.
Check your code man....
In the main method you are trying to remove the 4th element which is not there and hence the error.
In the remove() method you are trying to remove the 3rd element which is there and hence no error.
This question already has answers here:
ConcurrentModificationException using Iterator
(2 answers)
Closed 5 years ago.
I have the following code
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Arrays.stream("hello how are you".split(" ")).forEach(s -> list.add(s));
Iterator<String> it = list.iterator();
ListIterator<String> lit = list.listIterator();
while (it.hasNext()) {
String s = it.next();
if (s.startsWith("a")) {
it.remove();
} else {
System.out.println(s);
}
}
System.out.println(list);
// {here}
while (lit.hasNext()) {
String s = lit.next();
if (s.startsWith("a")) {
lit.set("1111" + s);
} else {
System.out.println(s);
}
}
System.out.println(list);
}
Here, after iterating through the Iterator, I try to iterate through the ListIterator. But the code throws a ConcurrentModificationException. I do the modification using the ListIterator only after the Iterator is done, but why do I get this exception.
When I initalize the ListIterator at {here} instead at the top, the code runs perfectly.
Isn't ConcurrentModificationException thrown when the list is being modified by two threads simultaneously?
Does initializing the iterator, create a lock on the list ? If yes, then why does Java let us to initialize an Iterator after it has already been initialized by another Iterator?
Isn't ConcurrentModificationException thrown when the list is being modified by two threads simultaneously ?
Not necessarily. The ConcurrentModificationException indicates that the list has been structurally changed (except by the Iterator's own remove method) after the Iterator was created. This could be due to multiple threads using the same list, or it could be due to an attempt to for example remove items from an ArrayList inside a for each loop without using an Iterator.
Does initializing the iterator, create a lock on the list ?
No, there are no locks. When the Iterator is created it records the modCount of the ArrayList (a crude representation of the list's state that is incremented on every structural change). If an iterator detects a change to the List's modcount that wasn't caused by its own methods the exception is thrown.
You are getting the exception from the second iterator because of the structural changes made to the list between the second iterator being instantiated and used.
why does Java let us to initialize an Iterator after it has already been initialized by another Iterator?
The ArrayList does not keep track of all the iterators that it has created, or their state. To do so would massively complicate the implementation. The modCount approach is not perfect and is a bit crude, but it is simple and identifies many real bugs.
You have to load the second iterator after you have used the first iterator. Otherwise the second iterator "thinks" the list hasn't been changed but in reality it did. Because the list got changed the second iterator react like "Wait a minute, that shouldn't be here/gone" and throws a ConcurrentModificationException.
It let you initialize the iterator at any time. When you don't change the content you might be even fine with it and you don't get a ConcurrentModificationException because nothing has been changed.
A ConcurrentModificationException may be thrown whenever you try to use an invalid iterator - which can happen whenever you create an iterator and then modify the underlying collection from a different access point. Here, lit is initialized and then the list is modified through it, so its invalidated, which explains the exception.
ListIterator throws ConcurrentModificationException it there is a modification in list after its creation. In your code you have created Iterator and ListIterator at the same time an later you are deleting something from the list which causes ConcurrentModificationException.
To avoid this changes your code to below one. You just need to move the ListIterator initialization after the operations of iterator.
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Arrays.stream("hello how are you".split(" ")).forEach(s -> list.add(s));
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.startsWith("a")) {
it.remove();
} else {
System.out.println(s);
}
}
System.out.println(list);
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
String s = lit.next();
if (s.startsWith("a")) {
lit.set("1111" + s);
} else {
System.out.println(s);
}
}
System.out.println(list);
}
This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 2 years ago.
I have this little piece of code and it gives me the concurrent modification exception. I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
List<String> s = new ArrayList<>();
ListIterator<String> it = s.listIterator();
for (String a : args)
s.add(a);
if (it.hasNext())
String item = it.next();
System.out.println(s);
}
}
To avoid the ConcurrentModificationException, you should write your code like this:
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
List<String> s = new ArrayList<String>();
for(String a : args)
s.add(a);
ListIterator<String> it = s.listIterator();
if(it.hasNext()) {
String item = it.next();
}
System.out.println(s);
}
}
A java.util.ListIterator allows you to modify a list during iteration, but not between creating it and using it.
I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.
Between creating the iterator and starting to use the iterator, you added arguments to the list that is to be iterated. This is a concurrent modification.
ListIterator<String> it = s.listIterator();
for (String a : args)
s.add(a); // concurrent modification here
if (it.hasNext())
String item = it.next(); // exception thrown here
Create the iterator AFTER you've finished adding elements to the list:
for (String a : args)
s.add(a);
ListIterator<String> it = s.listIterator();
if (it.hasNext())
String item = it.next();
From the JavaDoc: for ConcurrentModificatoinException: "it is not generally permssible for one thread to modify a Collection while another thread is iterating over it".
It simply means that if you still have an open iterator, you aren't allowed to modify the list because the iterator loop will break. Try moving ListIterator<String> it = s.listIterator(); till after the for loop.
You are not allowed to continue iterating over an iterator after the underlying list is modified. Here you create the iterator before adding a few items to s, and then proceed to do a hasNext() and a next() on it after the additions, leading to the ConcurrentModificationException
If the above solutions doesn't work properly. You can use old for-loop for iterating a List at the same time adding new items. See the example below:
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
ArrayList<AClass> aList = new ArrayList<AClass>(); // we will iterate this
// this will cause ConcurrentModificationException.
// Since we are iterating the list, at the same time modifying it.
/*for(AClass a: aList){
aList.add(someMethod(a));
}*/
// old fashion for-loop will help
int limit = aList.size();
for(int i=0; ctr<limit; ++i){
AClass a = aList.get(i);
aList.add(someMethod(a));
}
}
}
to understand this lets look at source of HashMap implementation:
public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{
which contains HashIterator as below:
private abstract class HashIterator {
...
int expectedModCount = modCount;
...
HashMapEntry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
....
}
every time you create a iterator:
a counter expectedModCount is created and is set to value of modCount as entry checkpoint
modCount is incremented in cases of use put/get (add/remove)
nextEntry method of iterator is checking this value with current modCount if they are different concurrent modification exception is throw
to avoid this u can:
convert map to an array (not recommended for large maps)
use concurrency map or list classes (CopyOnWriteArrayList / ConcurrentMap)
lock map (this approach removes benefits of multithreading)
this will allow you to iterate and add or remove elements at the same time without rising an exception
Concurrency map/list iterator is a "weakly consistent" iterator that will
never throw ConcurrentModificationException, and guarantees to
traverse elements as they existed upon construction of the iterator,
and may (but is not guaranteed to) reflect any modifications
subsequent to construction.
More info on CopyOnWriteArrayList
ConcurrentModificationException may arise in both single threaded environment and multi-threaded environment.
The main catch is that all the general purpose iterators (like the one used in ArrayList) are all FailFast iterators, which fails when we try to modify one list if one iterator is already iterating over it.
Solution - > Use CopyOnWriteArrayList if such scenario is needed by the requirement rather than using ArrayList.
For a complete demo for this, below mentioned code can be used.
We just need to change the implementation from CopyOnWriteArrayList to ArrayList.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* #author narif
*
*/
public class TestApp {
/**
* #param args
*/
public static void main(String[] args) {
List<String> testList = new ArrayList<>();
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add(6, "abcAtindex6");
int size = testList.size();
System.out.println("The Current List (ArrayList) is: " + testList);
System.out.println("The size of the List (ArrayList) is: " + size);
/* Comment the below lines to get the ConcurrentModificationException */
testList = new CopyOnWriteArrayList<>(testList);
for (String value : testList) {
System.out.println("The Value from ForEach Loop is: " + value);
/*
* Concurrent modification is happening here
* One iterator is iterating over the list while we are trying to add new values to
* the list so the results of the iteration are undefined under these circumstances.
* So teh fail fast iterators will fail and will throw the ConcurrentModificationException.
*/
testList.add("valueFromForLoop");
testList.add("anotherValueFromForEachLoop");
}
Iterator<String> it = testList.iterator();
while (it.hasNext()) {
String abc = it.next();
System.out.println(abc);
testList.add("Value from Iterator1");
testList.add("Value from Iterator2");
testList.add("Value from Iterator3");
testList.add("Value from Iterator4");
}
System.out.println("Did the modificationa and all after conevrting the ArrayList to CopyOnWriteArrayList.");
System.out.println("Calling the method to get the new List..");
testList = new CopyOnWriteArrayList<>(getTheList(testList));
for (String value : testList) {
System.out.println("The value returned from method is : " + value);
}
}
private static List<String> getTheList(List<String> pList) {
List<String> list = new CopyOnWriteArrayList<>(pList);
int i = 0;
for (String lValue : list) {
System.out.println("The list Passed is " + list);
i++;
list.add("localVaueFromMethod" + i);
list.removeAll(pList);
}
return list;
}
}
For more inifo follow this link this may be helpful alot ConcurrentModificationException Java Docs
This didn't work:
LinkedList<String> linkedList = new LinkedList<String>();
ListIterator listIterator = linkedList.listIterator();
linkedList.add("aa");
linkedList.add("bb");
This worked:
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("aa");
linkedList.add("bb");
ListIterator listIterator = linkedList.listIterator();
Have a look at oracle documentation page.
public class ConcurrentModificationException
extends RuntimeException
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible
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.
In your case, you have modified the collection after creating the iterator and hence you have encountered the exception.
If you change your code as per Stephen C answer, you won't get this error.
Note: I am aware of the Iterator#remove() method.
In the following code sample, I don't understand why the List.remove in main method throws ConcurrentModificationException, but not in the remove method.
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer toRemove) {
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer toRemove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
}
Here's why:
As it is says in the Javadoc:
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.
This check is done in the next() method of the iterator (as you can see by the stacktrace). But we will reach the next() method only if hasNext() delivered true, which is what is called by the for each to check if the boundary is met. In your remove method, when hasNext() checks if it needs to return another element, it will see that it returned two elements, and now after one element was removed the list only contains two elements. So all is peachy and we are done with iterating. The check for concurrent modifications does not occur, as this is done in the next() method which is never called.
Next we get to the second loop. After we remove the second number the hasNext method will check again if can return more values. It has returned two values already, but the list now only contains one. But the code here is:
public boolean hasNext() {
return cursor != size();
}
1 != 2, so we continue to the next() method, which now realizes that someone has been messing with the list and fires the exception.
Hope that clears your question up.
Summary
List.remove() will not throw ConcurrentModificationException when it removes the second last element from the list.
One way to handle it it to remove something from a copy of a Collection (not Collection itself), if applicable. Clone the original collection it to make a copy via a Constructor.
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For your specific case, first off, i don't think final is a way to go considering you intend to modify the list past declaration
private static final List<Integer> integerList;
Also consider modifying a copy instead of the original list.
List<Integer> copy = new ArrayList<Integer>(integerList);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
copy.remove(integer);
}
}
The forward/iterator method does not work when removing items. You can remove the element without error, but you will get a runtime error when you try to access removed items. You can't use the iterator because as pushy shows it will cause a ConcurrentModificationException, so use a regular for loop instead, but step backwards through it.
List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
int size= integerList.size();
//Item to remove
Integer remove = Integer.valueOf(3);
A solution:
Traverse the array in reverse order if you are going to remove a list element. Simply by going backwards through the list you avoid visiting an item that has been removed, which removes the exception.
//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
if (integerList.get(i).equals(remove) ) {
integerList.remove(i);
}
}
This snippet will always throw a ConcurrentModificationException.
The rule is "You may not modify (add or remove elements from the list) while iterating over it using an Iterator (which happens when you use a for-each loop)".
JavaDocs:
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.
Hence if you want to modify the list (or any collection in general), use iterator, because then it is aware of the modifications and hence those will be handled properly.
Hope this helps.
I had that same problem but in case that I was adding en element into iterated list.
I made it this way
public static void remove(Integer remove) {
for(int i=0; i<integerList.size(); i++) {
//here is maybe fine to deal with integerList.get(i)==null
if(integerList.get(i).equals(remove)) {
integerList.remove(i);
}
}
}
Now everything goes fine because you don't create any iterator over your list, you iterate over it "manually". And condition i < integerList.size() will never fool you because when you remove/add something into List size of the List decrement/increment..
Hope it helps, for me that was solution.
If you use copy-on-write collections it will work; however when you use list.iterator(), the returned Iterator will always reference the collection of elements as it was when ( as below )
list.iterator() was called, even if another thread modifies the collection. Any
mutating methods called on a copy-on-write–based Iterator or ListIterator
(such as add, set, or remove) will throw an UnsupportedOperationException.
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new CopyOnWriteArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
This runs fine on Java 1.6
~ % javac RemoveListElementDemo.java
~ % java RemoveListElementDemo
~ % cat RemoveListElementDemo.java
import java.util.*;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
~ %
In my case I did it like this:
int cursor = 0;
do {
if (integer.equals(remove))
integerList.remove(cursor);
else cursor++;
} while (cursor != integerList.size());
Change Iterator for each into for loop to solve.
And the Reason is:
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.
--Referred Java Docs.
Check your code man....
In the main method you are trying to remove the 4th element which is not there and hence the error.
In the remove() method you are trying to remove the 3rd element which is there and hence no error.
SITUATION: I have a TreeSet of custom Objects and I have also used a custom Comparator. I have created an iterator to use on this TreeSet.
TreeSet<Custom> ts=new TreeSet<Custom>();
Iterator<Custom> itr=ts.iterator();
while(itr.hasNext()){
Custom c=itr.next();
//Code to add a new element to the TreeSet ts
}
QUESTION: Well I want to know that if I add a new element to the TreeSet within the while loop, then will that new element get sorted immediately. In other words, if I add a new element within the while loop and it is less than the one which I am currently holding in c, then in the next iteration will I be getting the same element in c as in the last iteration?(since after sorting, the newly added element will occupy a place somewhere before the current element).
If you add an element during your iteration, your next iterator call will likely throw a ConcurrentModificationException. See the fail-fast behavior in TreeSet docs.
To iterate and add elements, you could copy first to another set:
TreeSet<Custom> ts = ...
TreeSet<Custom> tsWithExtra = new TreeSet(ts);
for (Custom c : ts) {
// possibly add to tsWithExtra
}
// continue, using tsWithExtra
or create a separate collection to be merged with ts after iteration, as Colin suggests.
You will get a java.util.ConcurrentModificationException if you add an element into the TreeSet inside while loop.
Set<String> ts = new TreeSet<>();
ts.addAll(Arrays.asList(new String[]{"abb", "abd", "abg"}));
Iterator<String> itr = ts.iterator();
while(itr.hasNext()){
String s = itr.next();
System.out.println("s: " + s);
if (s.equals("abd"))
ts.add("abc");
}
###Output
Exception in thread "main" java.util.ConcurrentModificationException
public static void main(String[] args) {
TreeSet<Integer> ts=new TreeSet<Integer>();
ts.add(2);
ts.add(4);
ts.add(0);
Iterator<Integer> itr=ts.iterator();
while(itr.hasNext()){
Integer c=itr.next();
System.out.println(c);
//Code
ts.add(1);
}
}
Exception in thread "main" java.util.ConcurrentModificationException
This will come to all collections like List , Map , Set
Because when iterator starts it may be putting some lock on it .
if you iterate list using iterator then this exception will come. I think otherwise this loop will be infinite as you are adding element whole iterating.
Consider without iterator:
public static void main(String[] args) {
List<Integer> list=new ArrayList<Integer>();
list.add(2);
list.add(4);
list.add(0);
for (int i = 0; i < 3; i++) {
System.out.println(list.get(i));
list.add(3);
}
System.out.println("Size" +list.size());
}
this will be fine .
In order to avoid the ConcurrentModificationException you might want to check out my UpdateableTreeSet. I have even added a new test case showing how to add elements during a loop. To be more exact, you mark new elements for a later, deferred update of the set. This works quite nicely. Basically you do something like
for (MyComparableElement element : myUpdateableTreeSet) {
if (someCondition) {
// Add new element (deferred)
myUpdateableTreeSet.markForUpdate(
new MyComparableElement("foo", "bar", 1, 2)
);
}
}
// Perform bulk update
myUpdateableTreeSet.updateMarked();
I guess this is quite exactly what you need. :-)
To prevent the ConcurrentModificationException while walking.
Below is my version to allow high frequency insertion into the TreeSet() and allow concurrently iterate on it. This class use a extra queue to store the inserting object when the TreeSet is being iterating.
public class UpdatableTransactionSet {
TreeSet <DepKey> transactions = new TreeSet <DepKey> ();
LinkedList <DepKey> queue = new LinkedList <DepKey> ();
boolean busy=false;
/**
* directly call it
* #param e
*/
void add(DepKey e) {
boolean bb = getLock();
if(bb) {
transactions.add(e);
freeLock();
} else {
synchronized(queue) {
queue.add(e);
}
}
}
/**
* must getLock() and freeLock() while call this getIterator function
* #return
*/
Iterator<DepKey> getIterator() {
return null;
}
synchronized boolean getLock() {
if(busy) return false;
busy = true;
return true;
}
synchronized void freeLock() {
synchronized(queue) {
for(DepKey e:queue) {
transactions.add(e);
}
}
busy = false;
}
}
While the question has already been answered, I think the most satisfactory answer lies in javadoc of TreeSet itself
The iterators returned by this class's iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, 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.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, >generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
To avoid the concurrent modification error that's bound to occur when you're doing the insertion, you could also create a temporary copy of the Set, iterate through the copy instead, and modify the original.