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.
Related
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);
I just have a general question about a program that I am doing.
I have a linked list and one of the instance variable is a version int to make sure there are no concurrent modification exceptions.
If I add an element to the linked list then I change the version.
I also use a custom iterator that iterates through the linked list that also has it's own version. When the linkedList iterator is created, it sets the iterator's version equal to the linkedList's version.
My question is:
If I remove an element with my Iterator should I change the iterators version as well?
Basically every method in the Iterator class it first checks to make sure the versions are the same, and if it's not it throws a new concurrent modification exception.
Does it matter if the iterator changes the list?
My question is: If I remove an element with my Iterator should I change the iterators version as well?
Yes, usually you should also change the version of your Iterator, as long as you want to allow modifications to the list by the Iterator. Otherwise you should throw a java.lang.UnsupportedOperationException.
Have a look at how the Iterator of java.util.LinkedList handles modifications: During the add and remove methods it first calls checkForComodification()
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
and at the end it will increase expectedModCount by one:
public void add(E e) {
checkForComodification();
[...]
expectedModCount++;
}
I have a very simple snippet of code that populates a vector, iterates through it, and then clears it. Here is basically what I'm trying in principle:
vector v = new Vector();
v.add(1);
v.add(2);
v.add(3);
ListIterator iter = v.listIterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
v.clear()
But I get a ConcurrentModificationException.
From reading up on this, apparently using "synchronized" in some fashion is the solution. But I'm seeing a couple different approaches and am wondering what is the best, simplest way to resolve this in my case (with no explicit threads involved)?
If no threads are involved, it's likely that the example you posted is incomplete.
This ConcurrentModificationException can happen simply if you modify the collection while 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 thow this exception.
And the docs for Vector.listIterator() explicitly state that:
Note that the list iterator returned by this implementation will throw an UnsupportedOperationException in response to its remove, set and add methods unless the list's remove(int), set(int, Object), and add(int, Object) methods are overridden.
(Well actually that the docs for AbstractList.listIterator(int); Vector doesn't redefine that.)
Let me shorten that code for you:
Vector<Integer> v = new Vector<Integer>();
v.add(1);
v.add(2);
v.add(3);
for (Integer i: v) {
System.out.println(i);
}
v.clear();
You shouldn't use listIterator() unless you do forward and backward navigation. For simple iteration use the iterator() method, preferably in the for-each style I show above (where the actual iterator object is hidden from you).
And don't use Vector!!! Use ArrayList instead.
According to http://download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html
The Iterators returned by Vector's
iterator and listIterator methods are
fail-fast: if the Vector 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. 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. The Enumerations returned
by Vector's elements method are not
fail-fast. 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
Could you give me an example to validate the above set of statements ?Im still unclear with fail fast behaviour of vector's method Iterator and ListIterator.? Confused :-((
if the Vector 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.
Here is an example:
import java.util.*;
public class Test {
public static void main(String[] args) {
List<String> strings = new Vector<String>();
strings.add("lorem");
strings.add("ipsum");
strings.add("dolor");
strings.add("sit");
int i = 0;
Iterator<String> iter = strings.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
// Modify the list in the middle of iteration.
if (i++ == 1)
strings.remove(0);
}
}
}
Output:
lorem
ipsum
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 Test.main(Test.java:18)
The program does the following:
Creates a Vector and gets an iterator
Calls next() twice.
Modifies the vector (by removing the first element)
Calls next() again (after the vector has been modified)
This causes a ConcurrentModificationException to be thrown.
Since Java's for-each loops rely on iterators these constructs may also throw ConcurrentModificationExceptions. The solution is to make a copy of the list before iterating (so you iterate over a copy) or to use for instance an CopyOnWriteArrayList like this:
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class Test {
public static void main(String[] args) {
List<String> strings = new CopyOnWriteArrayList<String>();
strings.add("lorem");
strings.add("ipsum");
strings.add("dolor");
strings.add("sit");
int i = 0;
Iterator<String> iter = strings.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
// Modify the list in the middle of iteration.
if (i++ == 1)
strings.remove(0);
}
}
}
Output:
lorem
ipsum
dolor
sit
A simple way to trigger a concurrent modification exception is
List<String> strings = new ArrayList<String>();
strings.add("a");
strings.add("b");
for(String s: strings)
strings.remove(s);
This triggers an exception because the collection is changed while iteration over the collection.
The reason the Iterator fails fast is to help you detect that a collection was modified concurrently (which these collections don't support) and help detect where the error occurred. If it didn't have this feature you could have subtle bugs which may not show a problem until much later in your code. (Making them much harder to race)
The newer concurrency collections handle concurrent modification differently and don't do this in general. They were introduced into core Java in 2004, i suggest you have a look at these newer collections.
BTW: Don't use Vector unless you have to.
Say you have a Vector of Integers containing 1-10 and you want to remove the odd numbers. You iterate over this list looking for odds and using the Iterators remove() method. After this you have some code that of course assumes there are no odd numbers in the Vector. If another thread modifies the vector during this process, there might sometimes actually be an odd number (depending on the race condition), breaking the code that comes after. Perhaps it doesn't even break right away; maybe it doesn't cause a problem until hours or days later -- very hard to troubleshoot. This is what happens with the elements() method.
Fail-fast means trying to detect this (potential) problem as soon as it occurs and sounding the alarm, which makes it much easier to troubleshoot. As soon as another thread is found to have modified the collection, an exception is thrown. This is what happens with the iterators.
The Iterators returned by iterator() and listIterator() actively watch for unexpected modifications to the underlying list. The Vector class (actually its parent AbstractList), increments a counter each time it is modified. When iterators for the Vector are created, they store a copy of the Vector's modification counter. Each time you call next() or remove() the Iterator compares it's stored value for the counter to the Vector's actual counter. If they differ, it throws a ConcurrentModificationException.
I went through the documentation(http://java.sun.com/javase/6/docs/api/java/util/Iterator.html) of Iterator.remove()
there remove() was described as
void remove()
Removes from the underlying collection the last element returned
by the iterator (optional operation).
This method can be called only once
per call to next. 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 this
method.
So can anybody tell what "optional" means.
Does this affect the robustness of operation?(Like c++ ,it does not guarantee the robustness of the operations.)
Why "optional" has been specified categorically here.
What does "modification" mean in the second line of documentation
behavior of an iterator is unspecified if the underlying collection is modified
#1: Optional means you can implement it or throw an UnsupportedOperationException
#2: This operation is optional because sometimes you just don't want your iterator's content to be modified. Or what do you understand by "robustness of operation"?
EDIT #4: behavior of an iterator is unspecified if the underlying collection is modified
Normally, you use an iterator by executing
List<String> c = new ArrayList<String>();
c.add("Item 1");
c.add("Item 2");
c.add("Item 3");
...
for (Iterator<String> i = c.iterator(); i.hasNext();)
{
String s = i.next();
...
}
If you now would want to remove an item while iterating through the list, and you would call
c.remove("Item 2");
this is not clean, possibly corrupts data in your List/Collection/... and should be avoided. Instead, remove() the item through the iterator:
i.remove();
First of all java.util.Iterator is an interface i.e. an agreement how classes that implement this interface interract with the rest of the world. It's their responsibility how they'll implement interaface's methods.
If the underlying data structure doesn't allow removal then remove() will throw an UnsupportedOperationException. For example, if you are iterating through a result set retrieved from a DB it does make sense not to implement this method.
If you iterate over some collection which is shared between concurrent threads and the other thread modifies the data iterating thread then will return undeterministic results.
It is described as being optional because not all collection classes that can give you an iterator implement the remove() method in the iterator they return. If the returned iterator doesn't implement it, an UnsupportedOperationException will be thrown.
The normal java.util.ArrayList, java.util.LinkedList and other standard collection classes all implement the remove() method in their iterators, so you can use it safely.