List.remove strange behaviour - java

Note: Not a duplicate of this question: Why am I not getting a java.util.ConcurrentModificationException in this example?. The question is, why the exception is not being thrown.
If we use foreach on List<String> and try to remove any element from it then it throws java.util.ConcurrentModificationException but why following code is not throwing the same exception and also not processing 2nd object of User?
public class Common {
public static void main(String[] args) {
User user1 = new User();
user1.setFirstname("Vicky");
user1.setLastname("Thakor");
User user2 = new User();
user2.setFirstname("Chirag");
user2.setLastname("Thakor");
List<User> listUser = new ArrayList<User>();
listUser.add(user1);
listUser.add(user2);
int count = 0;
for (User user : listUser) {
System.out.println(count + ":" + user.getFirstname()+" "+ user.getLastname());
count++;
listUser.remove(user);
}
}
}
The output is:
0:Vicky Thakor

Although the question is not an exact duplicate, the linked question: Why am I not getting a java.util.ConcurrentModificationException in this example? contains the answer.
The check that verifies whether to throw the exception is made when the next() method of the iterator has called, but this happens only if hasNext() returns true. In your case, when the list has two elements and you remove the first one in the first iteration the condition:
public boolean hasNext() {
return cursor != size(); // 1 != 1 after first iteration
}
is accidentally false, because cursor is at 1 and that's what size() is, at the moment. So next() is not called, and the exception is not being thrown.
Add a third element:
listUser.add(user2);
and the exception will be thrown. However, you should not rely on that behavior, because, as the documentation explains, it is not guaranteed:
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. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

As NESPowerGlove stated in the comment sections the interator returns a fail-fast iterator according to the java doc, but it includes this
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.
(Emphasis mine)
So, there is no guarantee that the exception will be thrown in the case of a modification.

Your loop could be rewritten as
Iterator<User> iterator = listUser.iterator();
while (iterator.hasNext()) {
User user = iterator.next();
System.out.println(count + ":" + user.getFirstname() + " " + user.getLastname());
listUser.remove(user);
}
and if we unroll the loop, it will look like
Iterator<User> iterator = listUser.iterator();
System.out.println(iterator.hasNext()); // prints true, loop executes
User user = iterator.next();
System.out.println(count + ":" + user.getFirstname() + " " + user.getLastname());
listUser.remove(user);
System.out.println(iterator.hasNext()); // prints false, loop stops
Until the second iterator.hasNext() call, collection is not modified, so all works as expected. Now the question is why the second iterator.hasNext() call returns false instead of throwing ConcurrentModificationException? Let's check ArrayList sources. I'll quote JDK 8 sources.
ArrayList.java, ArrayList's iterator declared at line 840 in class Itr. And it's hasNext() method is quite simple:
int cursor; // index of next element to return
...
public boolean hasNext() {
return cursor != size;
}
cursor is the index of the next element to return, size belongs to the outer ArrayList instance.
Checking for comodification implemented in the next() method.
Please note that you must not rely on this check in your own code. It designed to fight bugs, not provide you logic to rely upon. And it's not guaranteed to catch all your bugs (as demonstrated in your question). Probably performance is the reason why this check isn't implemented in hasNext() method.

Try this:
int count = 0;
for (User user : listUser) {
listUser.remove(user);
System.out.println(count + ":" + user.getFirstname()+" "+ user.getLastname());
count++;
}
for (User user : listUser) {
listUser.remove(user);
System.out.println(count + ":" + user.getFirstname()+" "+ user.getLastname());
count++;
}
I created the User class in less than 10 seconds. Contains two strings. But for the question, the User class is irrelevant. Assume Object and the problem remains. The key is to run this on debug and see what happens.
You will see the ConcurrentModificationException if you add the same for-each loop and try to iterate over the same list. The second time around, it would display:
0:Vicky Thakor
1:Chirag Thakor
Then throw the exception. Many people fail to remember that ConcurrentModificationException is a RuntimeException, and therefore, not documented on the API on the remove() method. The issue here is that you should trust the documentation. The documented safe way to remove an element while iterating is using the Iterator.

Related

Why the iterator throws a exception for Integer linkedlist [duplicate]

In the code below I have a try catch block that attempts to remove an element from a Vector, using Iterator. I've created my own class QueueExtendingVect that extends Vector and implements Iterator.
The variable qev1 is an instance of class QueueExtendingVect. I've already added a few elements to this Vector as well.
try
{
qev1.iterator().remove();
}
catch(UnsupportedOperationException e)
{
System.out.println("Calling Iterator.remove() and throwing exception.");
}
qev1.enqueue(ci);
qev2.enqueue(ci);
qcv1.enqueue(ci);
qcv2.enqueue(ci);
for (int i = 1; i < 5; i++)
{
if (i % 2 == 0)
{
qev1.enqueue(new CInteger(i+1));
qev2.enqueue(new CInteger(i+1));
qcv1.enqueue(new CInteger(i+1));
qcv2.enqueue(new CInteger(i+1));
}
else
{
qev1.enqueue(new Date(i*i));
qev2.enqueue(new Date(i*i));
qcv1.enqueue(new Date(i*i));
qcv2.enqueue(new Date(i*i));
}
}
In this code I add a few elements to the Vector qev1. The other variables are in other parts of the code.
However, when I run my program I get an IllegalStateException at runtime. I'm not sure what this means.
You haven't called next() on your Iterator, so it's not referring to the first item yet. You can't remove the item that isn't specified yet.
Call next() to advance to the first item first, then call remove().
#rgettman answer is correct but to give you imagination.
Our collection: |el1| |el2| |el3|
when you call iterator.next() it works this way:
|el1| iterator |el2| |el3|
so it jumps over the element and return reference to the element which was jumped (|el1|). So if we called iterator.remove() now, |el1| would be removed.
It's worth to add what #PedroBarros mentioned above - you can't call iterator.remove() two times without iterator.next() between them because IllegalStateException would be thrown.
Also when you create two iterators (iterator1, iterator2) then calling:
iterator1.next();
iterator1.remove();
iterator2.next();
will throw ConcurrentModificationException because iterator2 checks that collection was modified.
It will also call this exeption, If you add something to the list in iterator and then after it not calling it.next() again but removing the item

Concurrent Exception on Iterator.next() in Java [duplicate]

This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 1 year ago.
This is a code snippet to move to next element in the linked list. On debugging, itrPlaylist.next() is triggering a ConcurrentModificationException. I read that the list should not be modified while I am iterating. So, in this case, where did I go wrong? How can it be resolved?
Thanks in Advance.
public boolean nexxt() {
if(this.itrPlaylist.hasNext())
{
if(!bForward)
{
bForward = true;
itrPlaylist.next();
}
System.out.println("Now playing : " + itrPlaylist.next());
return true;
}
else
{
System.out.println("Reached end of " + this.getPlaylistName() + " playlist !");
}
return false;
}
Where is itrPlaylist is defined? Somethng like
itrPlaylist = list.iterator();
Above assignment should have happened after all the inserts have been done to the list. Looks like you have created one instance variable for itrPlaylist. And I think you might be doing
list.add(value);
after itrPlaylist has been initialized.
In that case, code will throw the above mentioned exception. This happens when some other code outside of iterator modifies the list when iterator is already initialized.

Collections remove method doesn't give Concurrent Modification Exception

I have read an article regarding removing elements from Collections from this link
As per my understanding iterator remove method prevents Concurrent modification exception then remove method of Collection.But when i try to run the below codde i am unable to get concurrentmoficationexception
List dayList= new ArrayList();
dayList.add("Sunday");
dayList.add("Monday");
dayList.add("Tuesday");
dayList.add("Wednesday");
dayList.remove("Tuesday");
Iterator itr=dayList.iterator();
while(itr.hasNext())
{
Object testList=itr.next();
if(testList.equals("Monday"))
{
dayList.remove(testList);
}
}
System.out.println(dayList);
}
As per javadoc the ConcurrentModicationException is thrown when we try to do any modification during iteartion.I am using collections remove method,but still there is no exception.But if I comment line dayList.remove("Tuesday");,exception is thrown.
Can anyone explain what is happening behind the scene in this code?
The fail-fast behavior of an iterator cannot be guaranteed. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. The iterator may or may not detect the invalid usage. 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.
if I comment line dayList.remove("Tuesday");,exception is thrown....
Actually this is not problem here. Problem is exception is occurring for middle value only.
‘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.
Your question is similar to this question.
Well add a Thursday and you would start getting the exception again :)
List dayList= new ArrayList();
dayList.add("Sunday");
dayList.add("Monday");
dayList.add("Tuesday");
dayList.add("Wednesday");
dayList.add("Thursday"); // Added by Kuldeep
dayList.remove("Tuesday");
Iterator itr=dayList.iterator();
while(itr.hasNext())
{
Object testList=itr.next();
if(testList.equals("Monday"))
{
dayList.remove(testList);
}
}
System.out.println(dayList);
So essentially that is because The fail-fast behavior of an iterator cannot be guaranteed. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Look at the documentation here.
EDIT : The exception is not thrown in your case is because in the following code:
if(testList.equals("Monday"))
{
dayList.remove(testList);
}
you are removing the second last element, which actually change the size or the dayList from 3 to 2. So the itr.hasNext() returns false after Monday is removed from the list and hence does not go into the loop for last entry i.e. Wednesday and avoids the call to itr.next(). You may try debugging the code to verify this behavior.

Iterator.remove() IllegalStateException

In the code below I have a try catch block that attempts to remove an element from a Vector, using Iterator. I've created my own class QueueExtendingVect that extends Vector and implements Iterator.
The variable qev1 is an instance of class QueueExtendingVect. I've already added a few elements to this Vector as well.
try
{
qev1.iterator().remove();
}
catch(UnsupportedOperationException e)
{
System.out.println("Calling Iterator.remove() and throwing exception.");
}
qev1.enqueue(ci);
qev2.enqueue(ci);
qcv1.enqueue(ci);
qcv2.enqueue(ci);
for (int i = 1; i < 5; i++)
{
if (i % 2 == 0)
{
qev1.enqueue(new CInteger(i+1));
qev2.enqueue(new CInteger(i+1));
qcv1.enqueue(new CInteger(i+1));
qcv2.enqueue(new CInteger(i+1));
}
else
{
qev1.enqueue(new Date(i*i));
qev2.enqueue(new Date(i*i));
qcv1.enqueue(new Date(i*i));
qcv2.enqueue(new Date(i*i));
}
}
In this code I add a few elements to the Vector qev1. The other variables are in other parts of the code.
However, when I run my program I get an IllegalStateException at runtime. I'm not sure what this means.
You haven't called next() on your Iterator, so it's not referring to the first item yet. You can't remove the item that isn't specified yet.
Call next() to advance to the first item first, then call remove().
#rgettman answer is correct but to give you imagination.
Our collection: |el1| |el2| |el3|
when you call iterator.next() it works this way:
|el1| iterator |el2| |el3|
so it jumps over the element and return reference to the element which was jumped (|el1|). So if we called iterator.remove() now, |el1| would be removed.
It's worth to add what #PedroBarros mentioned above - you can't call iterator.remove() two times without iterator.next() between them because IllegalStateException would be thrown.
Also when you create two iterators (iterator1, iterator2) then calling:
iterator1.next();
iterator1.remove();
iterator2.next();
will throw ConcurrentModificationException because iterator2 checks that collection was modified.
It will also call this exeption, If you add something to the list in iterator and then after it not calling it.next() again but removing the item

ArrayList remove error

I'm working on a project for school but i'm a little stuck right now
My problem is that i have an arrayList of Squares
Each Square has a value(from 0 to 100). Its starting value is 9999 so i can check if its is checked.
If a square is checked i want it to be removed from the arrayList.
So after a while there will be no Squares left.
there is a little bit of code where the first value is set so thats why i check if the value is 9999.
But i get an error. One that i havent seen before.
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
Vak = Square
this is my code:
while (!vakken.isEmpty()) { // check if empty
Iterator itrVak = vakken.iterator();
while (itrVak.hasNext()) {
Vak vak = (Vak) itrVak.next(); // here is get the error
if (vak.getValue() != 9999) {// check if square value is 9999
Collection checkVakken = vak.getNeighbour().values();
Iterator itre = checkVakken.iterator();
while (itre.hasNext()) {
Vak nextVak = (Vak) itre.next();
if (nextVak != null) {
if (nextVak.getValue() == 9999) {
nextVak.setValue(vak.getValue() + 1); // set value by its neighbour
vakken.remove(vak);
checkvakken.add(vak);
}
}
}
} else {
vakken.remove(vak);
checkvakken.add(vak);
}
}
}
You are removing elements from the collection while you are iterating it. As the iterator may produce unpredictable results in this situation, it fails fast throwing the exception you encountered.
You may only alter a collection through the iterator's methods while traversing it. There should be remove method on the iterator itself, that removes the current element and keeps the iterator intact.
While iterating, you should use Iterator instance for removing object:
itre.remove();
You can try like this:
itre.remove();
ITERATOR never lets you modify when you are iterating.. you need to use loops instead.. this happens coz you are using the Iterator, same time other thread is modifying the list...

Categories

Resources