If I write
String myFirstString = "a";
String mySecondString = "b";
List<String> lstOfStrings = new ArrayList<String>();
lstOfStrings.add(myFirstString);
lstOfStrings.add(mySecondString);
for (String value : lstOfStrings) {
if(value.equals("a")) {
lstOfStrings.remove("a");
System.out.println("removed successfully");
}
}
It works fine but,
If I change the order of insertion in list , it will gives java.util.ConcurrentModificationException see below code
String myFirstString = "a";
String mySecondString = "b";
List<String> lstOfStrings = new ArrayList<String>();
lstOfStrings.add(mySecondString);
lstOfStrings.add(myFirstString);
for (String value : lstOfStrings) {
if(value.equals("a")) {
lstOfStrings.remove("a");
System.out.println("removed successfully");
}
}
gives java.util.ConcurrentModificationException
Why such behavior occur in for each? I know there are many way like Iterator, CoppyOnWriteArraylist as resolution of ConcurrentModificationException Exception. but I want to know reason of this specific case. please explain.
I am going to guess that the implementation of the byte-code generated for the iterator syntactic sugar of for (val:collection) includes an optimization of checking that you are on the last element of the collection and not bothering to enter the iterator again. So if you remove an item next to last in the collection it will not throw the exception and just skip the last item. This is somewhat proven by 2 experiments:
add 3rd item to your first example and it will fail.
Modify it to delete 2nd item instead of the 1st and will complete "successfully" again.
UPDATE: ah, this question is a duplicate of
Why isn't this code causing a ConcurrentModificationException?
A Java for-each loop internally uses iterator of the collection.
The behavior of Java iterator is fail-fast which fails when any contents of the collection has been changed while looping through it.
For more information, I recommend to read the articles below.
http://www.jguru.com/faq/view.jsp?EID=221988
http://www.developersfusion.com/Articles/AD/F/53/ConcurrentModificationException---Fail-Fast-and-Fail-Safe-iterators.aspx
http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html
It is because of the way that the ArrayList's iterator is implemented.
When you remove the element before the last one the iterator will not iterate the last one anymore.
Try printing out each iteration
String myFirstString = "a";
String mySecondString ="b";
List<String> lstOfStrings = new ArrayList<String>();
lstOfStrings.add(myFirstString);
lstOfStrings.add(mySecondString);
for (String value : lstOfStrings) {
System.out.println("Iterating: " + value);
if(value.equals("a")){
lstOfStrings.remove("a");
System.out.println("removed successfully");
}
}
System.out.println(lstOfStrings);
The output is
Iterating: a
removed successfully
[b]
As you can see in the last System.out.printlnthe lstOfStringstill contains element "b", but it is not iterated.
And when you look at the Implementation of ArrayList you can see why.
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
....
}
The Iterator.hasNext() only checks if the actual cursor is not the size. So if you iterate through the list and remove string "a" the cursor points to the second element "b" but the size has been reduced to 1. So the second will not be iterated anymore.
This happens even in JDK 1.7 and I have not tested if this behavior still exists in 1.8.
When you use the Iterator.remove() method it will work, because the iterator is aware of the removal.
Iterator<String> iterator = lstOfStrings.iterator();
while (iterator.hasNext()) {
String value = iterator.next();
System.out.println("Iterating: " + value);
if (value.equals("a")) {
iterator.remove();
System.out.println("removed successfully");
}
}
Prints out:
Iterating: a
removed successfully
Iterating: b
There is no Exception in your first block of code snippet, because the loop will break out after the lstOfStrings.remove("a"), and before the interator.next() call. The iterator of the ArrayList is checking hasNext()by checking the return cursor != size, where the cursor is the current position in the iterator, that means after you remove the element: a from the list, the cursor increased: cursor++(cursor==1), but the size is decreased(you removed an element, size == 1). It does not throw Exception but it doesn't mean it is correct.
Think the following code:
for (String value : lstOfStrings) {
System.out.println("Iterating: " + value);
if(value.equals("a")){
lstOfStrings.remove("a");
System.out.println("removed successfully");
} else if (value.equals("b")) {
doSomethingOnB(value) // this won't be executed anyway!!!
}
}
And if you add one more elements into the lstOfStrings in the first code snippet, like: lstOfStrings.add("c"), it will throw the Exception you desire. :-)
The ConcurrentModificationException is thrown in your second block of code snippet, because it passed the hasNext() checking(cursor == 2, size == 1), then goes into the interator.next() call, which will check the modCount in the ArrayList and the expectedModCount in the Iterator, which represents count of modifications on the List elements size. Obviously, modeCount == 3 (2 adds and 1 remove), but the ArrayList.remove(Object) methods does not affect the expectedModCount in the ArrayList.Iterator, thus expectedModCount == 2, that is why it throws the Exception.
I am not sure whether it should be considered a bug in ArrayList, the root reason in your cases are the ArrayList's elements modification count is not synchronized with the Iterator's.
Some excerpts from ArrayList API -
With every addition and removal on list modCount is incremented.
For each loop's iterator call next() method for list size + 1 times in this case 3 times.
When lstOfStrings.remove("a"); is called modCount is set to 3.
At every next() iteration of iterator checkForComodification(); is called to check if there is any modification, since modification is found we get ConcurrentModificationException.
Why doesn't Iterator throw Exception then ?
Had there been call for checkForComodification(); after this ArrayList.this.remove(lastRet); It would have thrown same exception.
Related
it was known that can't use list.remove in foreach. there is a confuse for me that phase1 runs ok but phase2 was not. can someone explan this?
phase1
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}
System.out.println(list);
phase2
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
for (String item : list) {
if ("2".equals(item)) {
list.remove(item);
}
}
System.out.println(list);
Crazy. You found a bug in java. Such simple code - it boggles the mind.
Please refer to the source code of ArrayList. The bug is, specifically, in ArrayList.java on line 962.
Ordinarily, arraylists have a so-called 'mod counter'. Anytime you modify the arraylist in any way (be it adding, removing, clearing, etc), the modcounter is incremented by one.
Whenever you invoke .iterator() (which for (String item :list) also does at the very beginning, once), a new iterator object is made (see line 947 in the above link), and this iterator object stores the modcount as it was when the iterator is made.
The idea is that all iterator methods (which aren't many; only hasNext, next and remove) will first check if the modcount of the backing arraylist (the arraylist you got the iterator from by invoking its .iterator() method) is different from the remembered modcount, and if yes, the iterator will instant-abort with a ConcurrentModificationException.
The bug is that the hasNext method fails to do this. I think it's an optimization but it has led to a bug.
Thus, this bizarre interaction occurs:
List<String> list = new ArrayList<String>();
list has modcounter = 0.
list.add("1");
list.add("2");
modcounter is now 2.
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}
This is syntax sugar. javac compiles it as if it read:
Iterator<String> it$1 = list.iterator();
while (it$1.hasNext()) {
String item = it$1.next();
// your actual code inside the for loop here:
if ("1".equals(item)) {
list.remove(item);
}
}
So let's go through it on that basis:
Iterator<String> it$1 = list.iterator();
An iterator object is made; its expectedModCount field is set to 2, as that is the current modcount of list.
while (it$1.hasNext()) {
the position field of the iterator is 0, and the size of the backing list is 2. So, yes, there are more values to return. hasNext() returns true, the while loop will enter.
String item = it$1.next();
modcounter is checked. expectedModCount of the iterator is 2, the mod counter of the list is 2, so that check passes, item is set to "1", and the iterator's position field is incremented, so that is now 1.
if ("1".equals(item)) {
list.remove(item);
}
The item is indeed "1", so list.remove(item) is called. list updates its modcount to 3, its size to 1, and removes the "1" element from its backing array.
and now the weirdness ensues:
while (it$1.hasNext()) {
well, hasNext() does not check that expectedModCount of the iterator is still equal to the modCount of the list. If it had, this would have failed, but it doesn't do that. The iterator's position field is 1, and the list's size is also 1, so hasNext() returns false, and the while loop exits. That's it: We're out of the loop without ever hitting a ConcurrentModificationException.
In contrast, in the second snippet, you invoke next() twice on it$1 and then the element is removed. At that point, hasNext() is invoked, and then the iterator's position field is 2, the list's size is 1, and the specific check (line 962 of ArrayList) checks if listSize != iteratorPosition. It's not, thus, hasNext returns true (a bit odd). Therefore the while loop enters the body a third time, runs String item = it$1.next(), and the next() method does do a modCount check. expectedModCount is 2, list's modCount is 3, thus, CoModEx is thrown.
To reproduce this, you need to remove the second-to-last element on an arraylist like this. In your example list of 2 elements, that'd be the first element.
How do you actually remove items during iteration?
The right strategy is to use the remove method of iterator. You can't access the iterator in a for(:) loop, so write:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
if ("2".equals(item)) {
it.remove(); // this is how to do it!
}
}
remove() on an iterator is unique: Assuming the modcount check passes, it increments both the iterator's expected modcount as well as the backing list's mod count: It is the only way you can modify a list during iteration without having the iterator fail on you (well, that, and this bug you found).
Next steps
I'll file a bug over at openjdk for this issue.
Fast-Fail : meaning that if they detect
that the collection has changed since iteration began, they throw the unchecked
ConcurrentModificationException.
I have written a test example to demonsterate this:
String hi = "Hi";
list.add(hi);
list.add("Buy");
System.out.println("list before: " + list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
list.add("Good");
}
the output is:
list before: [Hi, Buy]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at thread.CollectionTest.main(CollectionTest.java:19)
which is expected. However, when an element is removed, the exception is not thrown:
List<String> list = new ArrayList<>();
String hi = "Hi";
list.add(hi);
list.add("Buy");
System.out.println("list before: " + list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
list.remove(hi);
}
Output:
list before: [Hi, Buy]
list after: [Buy]
Why is that? both cases the list is modified.
The point is that it is not hasNext() that checks for modification, but next(). In your "remove" scenario, you suppress the next call that would throw because there is no next element.
If you had 3 elements in the beginning, removing one would result in hasNext to be 'true'. Then the following next will throw the expected exception.
The JavaDoc points out that the "fail-fast" functionality works based on "best effort" and that it shall be used merely for detecting bugs rather than really depending on it for the program to behave correctly. Obviously because of side-effects like this one.
ConcurrentModificationException will throw, you can make some modifications in the list during iteration.
After doing the modification in the list during iteration, if you try to access the next() or remove() using iterator, then it verify the modCount and expectedModCount and count is not same then it throw ConcurrentModificationException .
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
This question already has answers here:
Why iterator.remove does not throw ConcurrentModificationException
(6 answers)
Closed 7 years ago.
Why is this legal:
for(int i=0; i < arr.size(); i++) {
arr.remove(i);
}
But using an iterator or the syntactic sugar of a for each results in a ConcurrentModificationException:
for(String myString : arr) {
arr.remove(myString);
}
Before everyone starts jumping on the bandwagon telling me to use iterator.remove(); I'm asking why the different behavior, not how to avoid the conc mod exception. Thanks.
Let's take a look at how, e.g., ArrayLists's iterator is implemented:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
public E next() {
checkForComodification();
int i = cursor;
if (i >= size) throw new NoSuchElementException();
// ...
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
// ...
ArrayList.this.remove(lastRet);
// ...
cursor = lastRet;
lastRet = -1;
}
Let's look at an example:
List list = new ArrayList(Arrays.asList(1, 2, 3, 4));
Iterator it = list.iterator();
Integer item = it.next();
We remove the first element
list.remove(0);
If we want to call it.remove() now, the iterator would remove number 2 because that's what field lastRet points to now.
if (item == 1) {
it.remove(); // list contains 3, 4
}
This would be incorrect behavior! The contract of the iterator states that remove() deletes the last element returned by next() but it couldn't hold its contract in the presence of concurrent modifications. Therefore it chooses to be on the safe side and throw an exception.
The situation may be even more complex for other collections. If you modify a HashMap, it may grow or shrink as needed. At that time, elements would fall to different buckets and an iterator keeping pointer to a bucket before rehashing would be completely lost.
Notice that iterator.remove() doesn't throw an exception by itself because it is able to update both the internal state of itself and the collection. Calling remove() on two iterators of the same instance collection would throw, however, because it would leave one of the iterators in an inconsistent state.
Looking at your code, I am assuming arr is a List. In the top loop you operate on the list directly, and "re-calibrate" your condition at the top when you check
i < arr.size()
So if you remove an element, i has to compare to a lesser value.
On the other hand, in the second case you operate on the collection after an iterator has been instantiated, and don't really re-calibrate yourself.
Hope this helps.
In the first one you are modifying an array that it's not being used as an iterator on your for loop.
In the second one you are trying to access to an array that it's being modified at the same time you are iterating with it on the loop. It's why it throws ConcurrentModificationException.
This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 3 years ago.
I am seeing a weird behavior.
List<String> li = new ArrayList<>();
li.add("a");
li.add("b");
li.add("c");
li.add("d");
li.add("e");
for(String str:li){
if(str.equalsIgnoreCase("d")){
li.remove(str); //removing second last in list works fine
}
}
But if i try to remove any other than second last in the list, i get ConcurrentModificationException. It came to my attention while reading "Oracle Certified Associate Java SE 7 Programmer Study Guide 2012" which incorrectly assumes that .remove() always works with an example of removing the second last in the list.
In a list, adding or removing is considered as a modification. In your case you have made
5 modifications(additions).
‘for each’ loop works as follows,
1.It gets the iterator.
2.Checks for hasNext().
public boolean hasNext()
{
return cursor != size(); // cursor is zero initially.
}
3.If true, gets the next element using next().
public E next()
{
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification()
{
// Initially modCount = expectedModCount (our case 5)
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Repeats steps 2 and 3 till hasNext() returns false.
In case if we remove an element from the list , it’s size gets reduced and modCount is increased.
If we remove an element while iterating, modCount != expectedModCount get satisfied
and ConcurrentModificationException is thrown.
But removal of second last object is weird. Lets see how it works in your case.
Initially,
cursor = 0 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
cursor = 1 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
cursor = 2 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
cursor = 3 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
In your case as you remove ‘d’ , size gets reduced to 4.
cursor = 4 size = 4 --> hasNext() does not succeed and next() is
skipped.
In other cases, ConcurrentModificationException will be thrown as modCount != expectedModCount.
In this case, this check does not take place.
If you try to print your element while iterating, only four entries will be printed. Last element is skipped.
Hope I made clear.
Don's use List#remove(Object) here since you are accessing elements from the List in for-each loop.
Instead use Iterator#remove() to remove an item from List:
for(Iterator<String> it=li.iterator(); it.hasNext();) {
String str = it.next();
if(str.equalsIgnoreCase("d")) {
it.remove(); //removing second last in list works fine
}
}
ConcurrentException is raised because of the fail fast behaviour of the ArrayList. This means you can not modify the list while iterating it except Iterator#remove() .
Refer http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
Please use Iterator#remove() method while removing elements from a List while looping . Internally the for-each loop will use the Iterator to loop through the Listand since the behavior of an Iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling Iterator's remove() method.You are getting the exception .
This loop :
for(String str:li){
if(str.equalsIgnoreCase("d")){
li.remove(str); //removing second last in list works fine
}
}
is basically
Iterator<String> itr = li.iterator();
while(itr.hasNext()){
String str = (String)itr.next();
if(str.equalsIgnoreCase("d")){
li.remove(str); //removing second last in list works fine
}
}
Why removing second last element doesn't throw exception ?
Because by removing the second last element you have reduced the size to the number of elements which you have iterated over. A basic hasNext() implementation is
public boolean hasNext() {
return cursor != size;
}
So in this case the cursor=size=4, so hasNext() evaluates to false and the loop breaks early before the concurrent modification check is performed in next(). The last element is never accessed in this case . You can check that by adding a simple OR condition in the if
if(str.equalsIgnoreCase("d") || str.equalsIgnoreCase("e")){
// last element "e" won't be removed as it is not accessed
li.remove(str);
}
But if you remove any other element next() is called which throws the ConcurrentModificationException.
If you really want to iterate over an ArrayList and remove elements then you should do it this way:
for(int index = yourArrayList.size() - 1; index >= 0; index--) {
if(yourCondition) {
yourArrayList.remove(index);
}
}
You can iterate "backwards" and remove elements, but not forward. So instead of iterating from the first element to the last, iterate from the last to the first.
Pseudo-code:
for(int i = list.size() -1; i >= 0; i--)
{
list.remove(i);
}
If you wish to remove all then.removeAll should do the trick rather than iterating through the collection. I think it is speedier too.
This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 3 years ago.
I have below two java class
import java.util.*;
public class ArrayListTest032 {
public static void main(String[] ar) {
List<String> list = new ArrayList<String>();
list.add("core java");
list.add("php");
list.add("j2ee");
list.add("struts");
list.add("hibernate");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
list.remove("php");
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
When I run above code I get below output.
core java
php
j2ee
struts
hibernate
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 ArrayListTest032.main(ArrayListTest032.java:20)
Which is expected as I am modifying the list while iterating. But in below java class same logic is executed by set family.
import java.util.*;
public class HashSetTest021 {
public static void main(String[] ar) {
Set<String> set = new HashSet<String>();
set.add("core java");
set.add("php");
set.add("j2ee");
set.add("struts");
set.add("hibernate");
Iterator<String> itr = set.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
set.remove("php");
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
And out put is.
hibernate
core java
j2ee
php
struts
There is no any ConcurrentModificationException.
I just want to know why same piece of code throws ConcurrentModificationException in case of list family, but there is no any ConcurrentModificationException in case of set family
This is a kind of 'retrograde' behavior, insomuch as iterators, once fully traversed, are not reusable, aka their hasNext method should return false when you reach the end of the list.
In this case though, the iterator returned by ArrayList.iterator is an internal implementation class, with code for hasNext as follows:
public boolean hasNext() {
return cursor != size;
}
So when you call hasNext in your second loop, it indicates (falsely) that there are more items to iterate over, because you executed an operation that changed the size of the list, after the first iteration. Semantically, you should not be able to continue iterating over items in the list after you reach the end of it, but due to this implementation detail it lets you proceed with the second while loop. Of course, at that point, you get a concurrent modification exception because of the change you made in the backing list.
On the other hand, the iterator used by your hash set has its hasNext implemented as follows:
public final boolean hasNext() {
return next != null;
}
This implementation happens not to be as 'vulnerable' to modifications made to the hash set after an iteration has been completed, and as such the hasNext method is better behaved.
This is a difference in the implementation: the iterator returned by the array list detects concurrent modifications even when it is positioned at the end, because it checks the length; iterators of the HashSet, TreeSet and LinkedList, on the other hand, do not detect this condition, because they check for being positioned at the end before checking for concurrent modification. The documentation allows iterators not to throw on concurrent modifications, so both approaches are valid.
Demo for the TreeSet.
Demo for the LinkedList.
Start by reading the JavaDoc for Iterator. Does it mention ConcurrentModificationException anywhere?
Now, read the JavaDoc for ConcurrentModificationException, and note the following (emphasis added):
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
Now look closely at your code. Your while loop iterates through all elements of the collection (even though the output of your first example doesn't indicate this, which tells me that either you've edited the output or this is not your actual code). At the time you remove the element, there are no more items to iterate, so the second loop should always exit immediately.
So, the conclusion is that the implementers of the list iterator have chosen that to throw that exception even when there are no more elements to iterate, while the implementers of the set iterator have chosen not to. Both cases are completely acceptable given the specifications.
public static void main(String[] ar) {
List<String> list = new ArrayList<String>();
list.add("core java");
list.add("php");
list.add("j2ee");
list.add("struts");
list.add("hibernate");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
list.remove("php");
/* while (itr.hasNext()) {
System.out.println(itr.next());
}*/
}
problem in itr object.it holds the list object reference
Hashset can throw a ConcurrentModificationException if you do anything to the set except through the iterator. However, there are a lot of heuristics around the itertor's fast-fail behavior with the goal to complete the iteration if at all possible. The JavaDocs seem pretty clear on it's behavior.
In case of list when we traverse it with first loop
Iterator itr = set.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
The cursor value and size will become same.Cursor contains value for total no of elements traversed and inside hashNext() method for list traversal contains code as:
public boolean hasNext() {
return cursor != size;
}
So after first while loop cursor == size.But after removing element from list size becomes (originalSize-1).So for next while loop it goes inside while and inside itr.next() method it checks for modcount modification and throws ConcurrentModificationException.
In case of Set it checks for next != null for every itr.hasnext() call.And after traversing first while loop next becomes null.Removing element from set does not affect next value as null and itr.hasNext will return next == null as true and hence it does not go inside while loop to check modcount modification.And hence it does not throw ConcurrentModification Exception.