I have following two classes of codes :
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestSet {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(90);
set.add(10);
set.add(20);
set.add(30);
System.out.println(set);
Iterator<Integer> itr = set.iterator();
while(itr.hasNext()){
Integer ob = itr.next();
if(ob.equals(10)){
set.add(11);
}
}
System.out.println(set);
}
}
output of above code is
[20, 90, 10, 30]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
at com.collection.TestSet.main(TestSet.java:18)
and another class
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestIntegerSet {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("90");
set.add("10");
set.add("20");
set.add("30");
System.out.println(set);
Iterator<String> itr = set.iterator();
while(itr.hasNext()){
String ob = itr.next();
if(ob.equals("10")){
set.add("11");
}
}
System.out.println(set);
}
}
while output of above code is
[90, 30, 20, 10]
[11, 90, 30, 20, 10]
I am not able to understand why there is strange behavior? Or I am doing something wrong?
I am trying to iterate using iterator but why its throwing concurrent modification exception for integer, while its showing proper value for String.
Both snippets are wrong. You should not make structural changes in a Collection
while iterating over it (to be exact, the only structural change you are allowed to make on the Set
during iteration is via the Iterator
's remove()
method).
The fact that one snippet throws ConcurrentModificationException
and the other doesn't is an artifact of the implementation of HashSet
.
The iteration order of the elements of a HashSet
is an implementation detail that depends on the hashCode()
of the elements. Integer
s and String
representations of those same Integer
s have different hashCode
s, and therefore the iteration order (as well as the location of the last added element within the order of iteration) is different for the two snippets.
The JDK detects concurrent modification and throws ConcurrentModificationException
whenever it can, but there are cases (like your second snippet) where it fails to do so.
If you change your first snippet to:
Set<Integer> set = new HashSet<>();
set.add(90);
set.add(10);
set.add(20);
set.add(30);
System.out.println(set);
Iterator<Integer> itr = set.iterator();
while(itr.hasNext()){
Integer ob = itr.next();
if(ob.equals(30)){
set.add(11);
}
}
System.out.println(set);
it won't throw an exception, since 11
will now be added after all the original 4 elements are iterated, so the Iterator
won't get a chance to throw an exception before iteration ends.
Similarly, the second snippet, that currently seems to work, will throw an exception if you change the condition from
if(ob.equals("10")){
set.add("11");
}
to
if(ob.equals("20")){
set.add("11");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With