Remove an Element from a List inside a loop [duplicate] - java

This question already has answers here:
Why am I not getting a java.util.ConcurrentModificationException in this example?
(10 answers)
Closed 8 years ago.
I'm trying to delete an element from an ArrayList inside a loop.
This is OK.
ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
for(Integer i: list){
if(i == 2)
list.remove(i);
}
But this is not, and throw concurrentMOdificationException.
ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
for(Integer i: list){
list.remove(i);
}
I don't understand why.
I just added another element, it is not OK either (throw concurrentMOdificationException).
ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4));
System.out.println(list);
for (Integer i : list) {
if (i == 2)
list.remove(i);
}

Use the Iterator class instead of the for-each loop.
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
Integer i = it.next();
it.remove();
}
http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
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.

You have to understand a little bit about what is going when use a for loop of this nature. It is really using a java.util.Iterator under the hood. This iterator will use the next() method to determine when iteration should stop, and the hasNext() method to retrieve the next element.
The kicker is that only next() checks for concurrent modification - hasNext() does not perform the check. In the first case, you wait until the second loop iteration to remove 2 from the list, and the next iteration finds the end of the list and exits. In the second case, you remove the 1 from the list during the first iteration, and the next iteration throws the exception when it tries to retrieve the next element.

Related

Different results with Iterator for Java Framework Collection

I have some questions about the different behaviors of Iterator on the main Java Framework Collection classes (not only for the List class).
List
If I write for-each I will have an exception:
Collection<String> cc= new ArrayList<>(3);
cc.add("Cio");
cc.add("Mio");
cc.add("Tio");
for (String s:cc) {
System.out.println(s);
cc.remove(s); //Exception
}
If I use the Iterator, I will have not an exception:
for (Iterator<String> it =cc.iterator(); it.hasNext();) {
String s =it.next();
if (s.startsWith("C"))
it.remove();
}
ArrayDeque
This is different for ArrayDeque, infact if I use for-each, I will
have not an exception:
ArrayDeque<String> greetings = new ArrayDeque<String>();
greetings.push("hello");
greetings.push("hi");
greetings.push("ola");
greetings.pop();
greetings.peek();
while (greetings.peek() != null)
System.out.print(greetings.pop());
But if I use the iterator, I will have an exception:
Iterator<String> it = greetings.iterator();
while(it.hasNext()) {
System.out.println(greetings.pop()); //Exception
}
Why? And does the iterator throw an exception for the other JFC collections, in particular: HashSet, TreeSet, LinkedList?
Thanks a lot!
A.
ArrayList
The list maintains a modCount field that is incremented each time a structural modification is done to the list.
Structural modifications are those that change the size of the list,
or otherwise perturb it in such a fashion that iterations in progress
may yield incorrect results.
Further...
If the value of this field changes unexpectedly, the iterator (or list
iterator) will throw a ConcurrentModificationException in response to
the next, remove, previous, set or add operations. This provides
fail-fast behavior, rather than non-deterministic behavior in the face
of concurrent modification during iteration.Use of this field by
subclasses is optional.
If a subclass wishes to provide fail-fast iterators (and list
iterators), then it merely has to increment this field in its add(int,
E) and remove(int) methods (and any other methods that it overrides
that result in a structural modification the list.
The two peice of list iteration code :
1.
for (String s:str1) {
System.out.println(s);
str1.remove(s);
}
and
2.
Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
i1.next();
i1.remove();
}
--may seem identically but are internally a bit different.
Its worth mentioning that the iterator of the list maitains a expectedModCount. That should be in sync with modCount when modifying the list while iterating.
In 1st case, String s:str1 gets the iterator, checks hasNext() and calls the next(), just like in the 2nd case. The difference comes in remove() method call. str1.remove(s); calls the remove method of the ArrayList. This increments the modCount but not expectedModCount. So in the second iteration, when next() is called it throws ConcurrentModificationException. On the other hand, in 2nd case, i1.remove(); calls the remove method from Iterator implementation in ArrayList. This increments the the modCount and expectedModCount and -- Bingo.
Note: Missing the i1.next(); in the second scenario will cause IllegalStateExcepton. This is because the cursor for the next element in the list is not updated.
TakeAway: Dont call the list.remove(element) method while iterating the list. This method is meant to be called when not in an iteration.
ArrayDeque
If you iterate the ArrayDeque like this:
Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
i1.next();
i1.remove();
}
-- it works the exact same way as its ArrayList counterpart.
When calling pop() or push() method of the ArrayDeque class, you don't actually iterate on the queue, you just modify the head or tail of the queue. This is just like calling remove() method of the ArrayList class when not in Iteration (not the remove() of Iterator of ArrayList). This doesn't qualify to be a structural modification. So it doesn't throw an Exception.
Refer this article.

Why is the design criteria for ConcurrentModificationException chosen only to be structural modification

I do understand that ConcurrentModificationExcpetion is thrown whenever there is a structural modification of the underlying collection after an iterator has been created. This seems to be a design decision.
I was wondering why update, through set() methods, is not considered for CME? Ultimately, the collection is getting updated and if iterator is created, traversal could still result in inconsistent results.
It is impossible to know the exact reasons for the design decision unless you were actually involved in making them.
I surmise that the reason might be that the iterator is designed to iterate the collection, rather than the values in the collection.
In other words, the iterator is like a "pointer" which will just be moved to point to each "space" in the collection in turn. By knowing something about the "shape" of the collection when the iterator is constructed, you know how to move the pointer to point to the next space in the collection.
If the value stored in a space changes, it doesn't really matter: that space and all other spaces in the collection are left unchanged.
However, if you change the shape of the collection via a structural modification, you've basically invalidated any assumptions that you have about where that pointer is pointing; short of doing something very clever, you may as well just give up and throw an exception.
Ultimately, the collection is getting updated and if iterator is created, traversal could still result in inconsistent results.
Actually, I think that the reason is that the set operations won't lead to inconsistent results. The code iterating the collection will either see the results of the set call's modification ... or not ... in a highly predictable fashion. And the code is guaranteed to still see each other element of the collection (i.e. apart from the one that you "set") exactly once.
By contrast, structural modifications on typical non-concurrent collections can cause the collection entries / elements to move around. For example:
An insertion or deletion in an ArrayList causes the elements in the backing array to change position.
An insertion in a HashMap or HashSet can cause resizing which causes the hash chains to be reconstructed.
In both cases, the structural modification can lead to elements being skipped, or seen more than once.
Please find my comments to your assumptions below.
I do understand that ConcurrentModificationException is thrown whenever there is a structural modification of the underlying collection after an iterator has been created.
Not exactly. The ConcurrentModificationException is actually thrown when the iterator attempts to fetch the next value and there has been a structural change in the underlying collection. (I want to stress that the ConcurrentModificationException is not thrown when invoking i.e. add or remove on the underlying collection).
Then, concerning your last assumption:
Ultimately, the collection is getting updated and if iterator is created, traversal could still result in inconsistent results.
I don't think this is correct. How could traversal still result in inconsistent results? If i.e. you modify the value at the i-th position of a list, you'll immediately see this change. The list is in fact modified, but not structurally modified. Only the value at the i-th position changes, but not the structure of the list (i.e. ArrayList's underlying array won't incur the risk of being resized, LinkedList won't allocate a new node, etc).
Finally, with regard to this sentence:
This seems to be a design decision.
Absolutely. It is 100% a design decision, and while I haven't been part of it, I'm certain that it has been driven by the aim of avoiding inconsistencies when traversing the underlying collection. Better than ending up with unexpected or inconsistent data, throw an exception as early as possible and let the user know.
However, the docs also mention that fail-fast iterators throw ConcurrentModificationException on a best-effort basis.
For example, consider the following code:
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
try {
Integer next = iterator.next();
System.out.println("iterator.next() = " + next);
System.out.println("BEFORE remove: " + list);
list.remove(0);
System.out.println("AFTER remove: " + list);
} catch (ConcurrentModificationException e) {
System.out.println("CME thrown, ending abnormally...");
System.exit(1);
}
}
Here we are attempting to remove the first element of the list while iterating over it. Upon execution, you'll see the following output:
iterator.next() = 1
BEFORE remove: [1, 2, 3]
AFTER remove: [2, 3]
CME thrown, ending abnormally...
This is the expected behavior. A ConcurrentModificationException is thrown when the iterator attempts to fetch an element from the list for the second time. This is because the implementation detects that a structural change has been made since the iterator was created. Thus, iterator.next() throws a CME.
However, as fail-fast iterators are not guaranteed to always throw a ConcurrentModificationException, but to do it only on a best-effort basis, there's a way to trick the implementation. Consider the code below, which is a modified version of the previous snippet (if you execute it, be warned that it will take some time until it finishes):
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
int structuralChanges = 0;
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
try {
Integer next = iterator.next();
System.out.println("iterator.next() = " + next);
System.out.println("BEFORE remove: " + list);
list.remove(0);
System.out.println("AFTER remove: " + list);
structuralChanges++;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
list.add(i);
structuralChanges++;
list.remove(list.size() - 1);
structuralChanges++;
}
list.add(0);
structuralChanges++;
System.out.println("Structural changes so far = " + structuralChanges);
} catch (ConcurrentModificationException e) {
System.out.println("CME NEVER thrown, so you won't see this message");
System.exit(1);
}
}
System.out.println("AFTER everything: " + list);
System.out.println("Program ending normally");
Here we are again removing the first element of the list while iterating it, but before the iterator fetches the next element, we're doing millions of structural modifications. In fact, we are doing Integer.MAX_VALUE * 2 + 1 structural modifications, if we consider all the list.add(i) and list.remove(list.size() - 1) calls inside the for loop, along with the list.add(0) call immediately after the for loop.
Additionally, we're keeping track of all structural modifications via the structuralChanges variable, which is incremented immediately after each structural modification.
Upon execution of the code above, you'll see the following output:
iterator.next() = 1
BEFORE remove: [1, 2, 3]
AFTER remove: [2, 3]
Structural changes so far = 0
iterator.next() = 3
BEFORE remove: [2, 3, 0]
AFTER remove: [3, 0]
Structural changes so far = 0
iterator.next() = 0
BEFORE remove: [3, 0, 0]
AFTER remove: [0, 0]
Structural changes so far = 0
AFTER everything: [0, 0, 0]
Program ending normally
As the output shows, no ConcurrentModificationException has been thrown.
Besides, after all structural modifications have been made, the value of the structuralChanges variable ends up being 0. This is because it is a variable of type int and it is overflowing and reaching 0 again, after being incremented Integer.MAX_VALUE * 2 + 2 times (Integer.MAX_VALUE * 2 + 1 times due to our artificial for loop and subsequent increment, plus 1 due to the list.remove(0) call of the original code).
Then, after all these Integer.MAX_VALUE * 2 + 2 structural modifications, when we call iterator.next() on the following iteration of the while loop, no ConcurrentModificationException is thrown, ever. We've tricked the implementation, so we can now see what happens to the data internally. (Internally, the implementation keeps track of the structural modifications by keeping an int count, as I've done with my structuralChanges variable).

Java concurrent modification exception is not coming while using collections remove method

I have seen in many places that it says when removing an element from an ArrayList while iterating, I should be using iterator remove method instead of collections remove method to avoid concurrent modification exception.
However, below code works fine using Java 1.8 Collection remove without giving concurrent modification exception. You can see that I am not using iterator here to remove the object.
List<MyObject> list = new ArrayList<MyObject>();
list.add(new MyObject());
list.add(new MyObject());
list.add(new MyObject());
for (int i=0; i<list.size(); i++) {
list.remove(i);
}
Your example will not throw an exception. It also won't remove all elements from the list, though.
What it really does
On first iteration, it removes index 0; 2 elements remain in the list
On second iteration, it removes index 1 (last element in fact); 1 element remains
Third iteration won't happen, because by then list.size() is 1 which is less than 2
At first, I thought it would throw an IndexOutOfBoundsException, but the fact that list.size() is evaluated at the start of each iteration ensures that it won't.
Why it doesn't throw ConcurrentModificationException
Because you're not using an iterator.
This exception is thrown if you iterate the list using an iterator, then modify (e.g. delete from) the list, and then try to advance the iterator, like this:
Iterator<MyObject> it = list.iterator();
while (it.hasNext()) {
list.remove(it.next());
}
As #Ferrybig noted, even in such case the iterator might not actually throw an exception - see related question.

ConcurrentModificationException when deleting an element from ArrayList

Java is throwing ConcurrentModificationException when I am running the following code. Any idea why is that?
ArrayList<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
list1.add("Good Evening");
for (String s : list1){
list1.remove(2);
System.out.println(s);
}
If you take a look at documentation of ConcurrentModificationException you will find that
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify
a Collection while another thread is iterating over it
...
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.
Important thing about this exception is that we can't guarantee it will always be thrown as stated in documentation
Note that fail-fast behavior cannot be guaranteed as it is, generally
speaking, impossible to make any hard guarantees in the presence of
unsynchronized concurrent modification. Fail-fast operations throw
ConcurrentModificationException on a best-effort basis.
Also from ArrayList documentation
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.
(emphasis mine)
So you can't manipulate content of Collection (in your case List) while iterating over it via enhanced for loop because you are not doing it via iterator for-each is using internally.
To solve it just get your own Iterator and use it in your loop. To remove elements from collection use remove like in this example
Iterator<String> it = list1.iterator();
int i=0;
while(it.hasNext()){
String s = it.next();
i++;
if (i==2){
it.remove();
System.out.println("removed: "+ s);
}
}
form the doc you can read
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify
a Collection while another thread is iterating over it. In general,
the results of the iteration are undefined under these circumstances.
Some Iterator implementations (including those of all the general
purpose collection implementations provided by the JRE) may choose to
throw this exception if this behavior is detected. Iterators that do
this are known as fail-fast iterators, as they fail quickly and
cleanly, rather that risking arbitrary, non-deterministic behavior at
an undetermined time in the future.
further more, suppose that you can remove item 2 at each iteration. You will end up in a index out of bound exception:
at first iteration you remove item #2 ("Good evening") and list size become 1 (item 0 "hello" and item 1 "World")
at next iteration you remove item #2 which actually does not exist in your list. Your list is indeed of size two, but counter starts from 0, thus you end up removing something which is not there: this is an example of the non-deterministic behavior.
You cann't iterating over an list after the underlying list is modified.if you do that its give you ConcurrentModificationException
to resolve this issue use java.util.ListIterator for iteration of list.
ListIterator<String> it = list1.listIterator();
for (String s : list1) {
if (it.hasNext()) {
String item = it.next();
System.out.println(item);
}
}
You can't delete an item with ArrayList's remove() method while iterating over it. Use Iterator if you want to delete the item also while iterating.
But you are deleting an item based on index then simply moving below line outside the loop will solve your problem.
list1.remove(2);

ConcurrentModificationException when clearing a sub list [duplicate]

This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 3 years ago.
Why does the following code throw ConcurrentModificationExcrption, when I clear the sub List after the master List, but not if I clear the sub list and then the master List?
ArrayList<Integer> masterList = new ArrayList<Integer>();
List<Integer> subList;
// Add some values to the masterList
for (int i = 0; i < 10; i++) {
masterList.add(i * i);
}
// Extract a subList from the masterList
subList = masterList.subList(5, masterList.size() - 1);
// The below throws ConcurrentModificationException
masterList.clear();
subList.clear(); // Exception thrown in this line
// The below doesn't throw any exception
subList.clear();
masterList.clear(); // No exception thrown. Confused??
SubList is not an independent entity, but it is just giving a view of the original list, and internally refers to same list. Hence, its design seem to be such that if underlying list is modified structurally (addition/removal of elements), it is not able to fulfill its contract.
As can be seen here in the source code of SubList, the method checkForComodification checks whether the underlying list has been modified, and thus if the modCount (number of times the list has been structurally modified) value of SubList is not same as parent ArrayList, then, it throws ConcurrentModificationException
So, clearing parent ArrayList from which SubList was created can result in the certain operations of SubList to result in ConcurrentModificationException
subList is a view over the masterList. There is just 1 underlying collection. Now masterList is kind of a superset of sublist. So,
sublist cannot exist if masterlist's elements are removed //exception case
masterlist can exist if sublist's elements are removed //OK
acording to ArrayList doc subList() returns a sublist that is backed by the original ArrayList, so if the original changes so does the subList, when you execute subList.clear() the sublist itself doesn't exist anymore.
From the API docs:
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
Undefined semantics means of course that it is allowed to throw an exception (and indeed this is probably the wisest course of action).
So you can change the size of the sublist and have those changes reflected in the main list, but the reverse isn't true.

Categories

Resources