Why does this code throw ConcurrentModificationException? - java

Write a method removeEvenLength that takes a Set of strings as a parameter and that removes all of the strings of even length from the set.
My solution:
public static void removeEvenLength(Set<String> set) {
for(String word : set) {
if(word.length() % 2 == 0) {
set.remove(word);
}
}
}
Input:
[foo, buzz, bar, fork, bort, spoon, !, dude]
Output:
ConcurrentModificationException on line 2:
java.util.ConcurrentModificationException
at java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1115)
at java.util.TreeMap$KeyIterator.next(TreeMap.java:1169)
at removeEvenLength (Line 2)
So I can solve it by creating an Iterator. But I want to know why the above code doesn't work?
EDIT:
Iterator doesn't work either:
public static void removeEvenLength(Set<String> set) {
Iterator<String> i = set.iterator();
while(i.hasNext()) {
String word = i.next();
if(word.length() % 2 == 0) {
set.remove(word);
}
}
}
Same error.

In this iteration iterator object is implicitly created. When you have iterator you can change collection just from iterator. In this case you are removing object directly, that's why this exception is thrown.
Create iterator, and remove object with iterator:
iterator.remove(); // removes current element

To understand why ConcurrentModificationException occurs, you will have understand the concept of fail-fast iteration. If a thread is iterating over a collection, and it realizes that the collection is being modified as the iteration is going on, the iterator will throw an exception rather than "probably" cause any integrity problems later on in the code.
Of course, not all iterators follow this approach, and using the Java Iterator will almost always ensure that the iteration never fails on modification.
To remove an element using the iterator, use this code
Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
String obj = iter.next();
if(<removal_condition_here>) {
iter.remove();
}
}

Related

Not getting Concurrent modification exception [duplicate]

Note: I am aware of the Iterator#remove() method.
In the following code sample, I don't understand why the List.remove in main method throws ConcurrentModificationException, but not in the remove method.
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer toRemove) {
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer toRemove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
}
Here's why:
As it is says in the Javadoc:
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.
This check is done in the next() method of the iterator (as you can see by the stacktrace). But we will reach the next() method only if hasNext() delivered true, which is what is called by the for each to check if the boundary is met. In your remove method, when hasNext() checks if it needs to return another element, it will see that it returned two elements, and now after one element was removed the list only contains two elements. So all is peachy and we are done with iterating. The check for concurrent modifications does not occur, as this is done in the next() method which is never called.
Next we get to the second loop. After we remove the second number the hasNext method will check again if can return more values. It has returned two values already, but the list now only contains one. But the code here is:
public boolean hasNext() {
return cursor != size();
}
1 != 2, so we continue to the next() method, which now realizes that someone has been messing with the list and fires the exception.
Hope that clears your question up.
Summary
List.remove() will not throw ConcurrentModificationException when it removes the second last element from the list.
One way to handle it it to remove something from a copy of a Collection (not Collection itself), if applicable. Clone the original collection it to make a copy via a Constructor.
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For your specific case, first off, i don't think final is a way to go considering you intend to modify the list past declaration
private static final List<Integer> integerList;
Also consider modifying a copy instead of the original list.
List<Integer> copy = new ArrayList<Integer>(integerList);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
copy.remove(integer);
}
}
The forward/iterator method does not work when removing items. You can remove the element without error, but you will get a runtime error when you try to access removed items. You can't use the iterator because as pushy shows it will cause a ConcurrentModificationException, so use a regular for loop instead, but step backwards through it.
List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
int size= integerList.size();
//Item to remove
Integer remove = Integer.valueOf(3);
A solution:
Traverse the array in reverse order if you are going to remove a list element. Simply by going backwards through the list you avoid visiting an item that has been removed, which removes the exception.
//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
if (integerList.get(i).equals(remove) ) {
integerList.remove(i);
}
}
This snippet will always throw a ConcurrentModificationException.
The rule is "You may not modify (add or remove elements from the list) while iterating over it using an Iterator (which happens when you use a for-each loop)".
JavaDocs:
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.
Hence if you want to modify the list (or any collection in general), use iterator, because then it is aware of the modifications and hence those will be handled properly.
Hope this helps.
I had that same problem but in case that I was adding en element into iterated list.
I made it this way
public static void remove(Integer remove) {
for(int i=0; i<integerList.size(); i++) {
//here is maybe fine to deal with integerList.get(i)==null
if(integerList.get(i).equals(remove)) {
integerList.remove(i);
}
}
}
Now everything goes fine because you don't create any iterator over your list, you iterate over it "manually". And condition i < integerList.size() will never fool you because when you remove/add something into List size of the List decrement/increment..
Hope it helps, for me that was solution.
If you use copy-on-write collections it will work; however when you use list.iterator(), the returned Iterator will always reference the collection of elements as it was when ( as below )
list.iterator() was called, even if another thread modifies the collection. Any
mutating methods called on a copy-on-write–based Iterator or ListIterator
(such as add, set, or remove) will throw an UnsupportedOperationException.
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new CopyOnWriteArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
This runs fine on Java 1.6
~ % javac RemoveListElementDemo.java
~ % java RemoveListElementDemo
~ % cat RemoveListElementDemo.java
import java.util.*;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
~ %
In my case I did it like this:
int cursor = 0;
do {
if (integer.equals(remove))
integerList.remove(cursor);
else cursor++;
} while (cursor != integerList.size());
Change Iterator for each into for loop to solve.
And the Reason is:
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.
--Referred Java Docs.
Check your code man....
In the main method you are trying to remove the 4th element which is not there and hence the error.
In the remove() method you are trying to remove the 3rd element which is there and hence no error.

Cannot remove hashset in java [duplicate]

This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 8 years ago.
i got a problem with hashset, I cannot remove a hashset, and here is the code
//take stopword list from file
public void stopWordList(){
openFile("D:/ThesisWork/Perlengkapan/stopword.txt");
while(x.hasNext()){
String a = x.nextLine();
a = a.toLowerCase();
stopWords.add(a);
}
}
//the method to remove stopword
public void stopWordRemoval(){
stopWordList();
//if the word in the streams set is equal to stopword, it should be removed
for(String word:streams){
for(String sw:stopWords){
if(word.equals(sw)){
streams.remove(word);
}
}
}
But, it gives me an exception, it says like :
Exception in thread "main" java.util.ConcurentModificationException, could anyone help me? thanks :)
This is because the foreach loop (for (Whatever x: something)) internally creates an Iterator.
And when you remove from the Iterable (the something above) being iterated, a well-behaved Iterator will detect that "hey, you have modified my babies beyond my knowledge" and throw this exception.
What you should do is this:
final Iterator<String> iterator = stream.iterator();
String word;
while (iterator.hasNext()) {
word = iterator.next();
if (stopWords.contains(word))
iterator.remove(); // This is safe: an iterator knows how to remove from itself
}
you are performing a concurrent modification - you are iterating over a collection and modifiying it not by the iterator, you should transform your code to this:
for (Iterator<String> it = streams.iterator(); it.hasNext();) {
String word = it.next();
for (String sw : stopWords) {
if (word.equals(sw)) {
it.remove();
break;
}
}
}

Java Concurrent Modification Exception Error

Im playing around with some code for my college course and changed a method from
public boolean removeStudent(String studentName)
{
int index = 0;
for (Student student : students)
{
if (studentName.equalsIgnoreCasee(student.getName()))
{
students.remove(index);
return true;
}
index++;
}
return false;
}
To:
public void removeStudent(String studentName) throws StudentNotFoundException
{
int index = 0;
for (Student student : students)
{
if (studentName.equalsIgnoreCase(student.getName()))
{
students.remove(index);
}
index++;
}
throw new StudentNotFoundException( "No such student " + studentName);
}
But the new method keeps giving a Concurrent Modification error. How can I get round this and why is it happening?
It is because you continue traversing the list after performing remove().
You're reading and writing to the list at the same time, which breaks the contract of the iterator underlying the foreach loop.
Use Iterator.remove()
for(Iterator<Student> iter = students.iterator(); iter.hasNext(); ) {
Student student = iter.next();
if(studentName.equalsIgnoreCase(student.getName()) {
iter.remove();
}
}
It is described as the following:
Returns the next element in the iteration.
Throws NoSuchElementException if the iteration has no more elements.
You can use Iterator.hasNext() to check if there is a next element available.
foreach construct uses an underlying Iterator.
In the second method you continue to iterate even after removing an item from the list. This is resulting in the exception that you see. Take a look at this statement taken from ConcurrentModificationException documentation:
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.
You are not allowed to remove an element from your collection while you iterate over it. The iterator detects a structural change during its usage, and throws the exception. Many collections are implemented in such a way.
Use the iterator directly instead:
Iterator<Student> it = students.iterator();
while (it.hasNext()) {
Student student = it.next();
if (studentName.equalsIgnoreCase(student.getName())) {
it.remove();
return true;
}
}
return false;
you can avoid concurrent modification error buy just breaking the loop after removing the element or if the method has a return type return a value after removing the element.
This error occurs because you are trying to alter the size of a collection while you are iterating it. If you have 10 students, you start your loop expecting to go through 10 iterations. When you remove a student, how many iterations do still need to go? The answer obviously depends on where you removed your student from the list and where you currently are in your iteation. Obviously, java cannot know this.
To get around this, you must use an iterator. You can accomplish this as follows:
Iterator<Student> studentsIterator;
for(studentsIterator = students.iterator(); studentsIterator.hasNext();)
{
Student student = studentsIterator.next();
if(student... /* condition */)
{
studentIterator.remove(); //This removes student from the collection safely
}
}
You are not allowed to remove an element from students collection while iterating through it.
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.
http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html
Try changing to
Iterator<Student> itr = students.iterator();
while (itr.hasNext()) {
Student student = itr.next();
if (studentName.equalsIgnoreCase(student.getName()))
{
itr.remove();
}
}
If you want to remove inside a loop you should use an iterator and its remove method
public boolean removeStudent(String studentName)
{
Iterator<Student> itS = students.iterator();
while(itS.hasNext())
{
Student student = itS.next();
if (studentName.equalsIgnoreCasee(student.getName()))
{
itS.remove();
return true;
}
}
return false;
}
You shouldn't delete objects from a collection while using
a for-each statement - this will cause exceptions as your iterator faces a changed collection in the course of its iterations. (the for loop)
either use a regular for loop (for int i = 0; i < 100; i++) etc...
or keep the objects to remove in a list, and remove them outside of the for loop.
Also, you remove the object by index where index is : 0 , 1 , 2
but index should actaully be the index of the student.

Java - Collection.remove() behaves differently in different conditions

This is a follow up to my previous question :
Collection - Iterator.remove() vs Collection.remove()
The below two pieces of code , which apparently differs only by a single line , but one throws exception and other don't . Can you please explain the difference ?
List<String> list = new ArrayList<String>
(Arrays.asList("noob1","noob2","noob3"));
System.out.println(list);
for (String str : list) {
if (str.equals("noob2")) {
list.remove(str);
}
}
runs fine , but if i change the condition to
if (!str.equals("noob2"))
the code throws exception !
What happens in this situation is you are removing the second list element.
List<String> list = new ArrayList<String>
(Arrays.asList("noob1", "noob2", "noob3", "noob4"));
System.out.println(list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
if (str.equals("noob3")) {
System.out.println("Checking "+str);
list.remove(str);
}
}
System.out.println(list);
prints
[noob1, noob2, noob3, noob4]
Checking noob1
Checking noob2
Checking noob3
[noob1, noob2, noob4]
By removing the second last element you have reduced the size to the number of elements which you have iterated over.
// from ArrayList.Itr
public boolean hasNext() {
return cursor != size;
}
This causes the loop to exit early before the concurrent modifcation check is performed in next(). If you remove any other element next() is called and you get a CME.
BTW Something which also bypasses the check is
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
System.out.println("Checking "+str);
if (str.equals("noob2")) {
list.remove("noob1");
list.remove("noob3");
}
}
as long as the size of the collection is the same as the index it is up to, the check is not performed.
The for loop is just a simplified syntax for an iterator scan of the list. The iterator may throw an exception if the list is modified under it, but it is not guaranteed. Because of hasNext, iterators are often working one element ahead, making the first case less likely to be affected by list modification. By the time "noob2" is removed, the iterator already knows about "noob3".
Actually you should never remove collections' elements during "casual" iterating. When you have to modify your collection in some loop you have to use iterator to make these operations.
public class Test {
public static void main(String... args) {
List<String> list = new ArrayList<String>(Arrays.asList("noob1", "noob2", "noob3"));
System.out.println(list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String str = iterator.next();
if (!str.equals("noob2")) {
iterator.remove();
}
}
System.out.println(list);
}
}
I suppose the exception is thown because you are trying to change a collection you are looping on... and not because the if condition.
I suggest you to create a new list only containing the items that verify the condition. Add them to the new list and avoid to change the original collection.
It's because you are trying to remove from a Collection you are currently iterating through. Making a minor alteration you can do what you want to do:
String[] strValues = {"noob1","noob2","noob3"}; // <<< Array
List<String> list = new ArrayList<String>(Arrays.asList(strValues));
System.out.println(list);
for (String str : strValues) { // << List is duplicate of array so can iterate through array
if (!str.equals("noob2")) {
list.remove(str);
}
}
That should work. Hopefully
Well, your first case doesn't throw the Exception because, the iterator returns false for Iterator.hasNext() at index 2 as you remove the element at index 1.
Iterator<String> itr = list.iterator();
while(itr.hasNext()){
String s= itr.next();
if(s.equals("noob2")){
list.remove(s); // size of the list is 2 here
System.out.println(itr.hasNext());// this returns false as it doesn't have anything at index 2 now.(on 2nd iteration )
}
}
You can test it clearly using a simple for-loop:
for (int i=0; i<list.size(); i++) {
if (list.get(i).equals("noob2")) {
System.out.println(list.get(i));
System.out.println(list.size());
list.remove(list.get(i));
System.out.println(list.size());
}
}
Output:
[noob1, noob2, noob3]
noob2
3
2
Notice the size of the list after you remove the element, which fails after incrementing. 2<2 which is false

ConcurrentModificationException when using iterator and iterator.remove()

private int checkLevel(String bigWord, Collection<String> dict, MinMax minMax)
{
/*value initialised to losing*/
int value = 0;
if (minMax == MinMax.MIN) value = 1;
else value = -1;
boolean go = true;
Iterator<String> iter = dict.iterator();
while(iter.hasNext())
{
String str = iter.next();
Collection<Integer> inds = naiveStringSearch(bigWord, str);
if(inds.isEmpty())
{
iter.remove();
}
for (Integer i : inds)
{
MinMax passin = minMax.MIN;
if (minMax == MinMax.MIN) passin = minMax.MAX;
int value2 = checkLevel(removeWord(bigWord, str, i), dict, passin);
if (value2 == -1 && minMax == minMax.MIN)
{
value = -1;
go = false;
}
if (value2 == 1 && minMax == minMax.MAX)
{
value = 1;
go = false;
}
}
if (go == false) break;
}
return value;
}
Error:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:810)
at java.util.HashMap$KeyIterator.next(HashMap.java:845)
at aStringGame.Main.checkLevel(Main.java:67)
at aStringGame.Main.test(Main.java:117)
at aStringGame.Main.main(Main.java:137)
What's the problem here?
Something somewhere is modifying dict. I suspect it might be happening inside this call:
int value2 = checkLevel(removeWord(bigWord, str, i), dict, passin);
^^^^
edit Basically, what happens is that the recursive call to checkLevel() modifies dict through another iterator. This makes the outer iterator's fail-fast behaviour to kick in.
You can't modify a Collection while you're iterating over it with an Iterator.
Your attempt to call iter.remove() breaks this rule (your removeWord method might, too).
You CAN modify a List while iterating IF you use a ListIterator to iterate.
You can convert your Set to a List and use a List iterator:
List<String> tempList = new ArrayList<String>(dict);
ListIterator li = tempList.listIterator();
Another option is to keep track of the elements you want to remove while iterating.
You could place them in a Set, for example.
You could then call dict.removeAll() after your loop.
Example:
Set<String> removeSet = new HashSet<String>();
for (String s : dict) {
if (shouldRemove(s)) {
removeSet.add(s);
}
}
dict.removeAll(removeSet);
When using a for each loop you are not allowed to modify the Collection you are iterating inside the loop. If you need to modify it, use a classic for loop
This is a common occurance in all Collections classes. For instance the entry in TreeSet uses failfast method.
The iterators returned by this class's iterator method are fail-fast:
if the set is modified at any time after the iterator is created, in
any way except through the iterator's own remove method, 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.
http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html

Categories