I wanted to display the numbers occuring in a character list and then remove that number. Here is my code:
package mytrials;
import java.util.ArrayList;
import java.util.ListIterator;
public class MyTrials {
public static void main(String[] args) {
ArrayList<Character> list = new ArrayList<Character>();
list.add('a');
list.add('1');
list.add('5');
System.out.println(list.size());
for( ListIterator i = list.listIterator(list.size()); i.hasPrevious();){
Character c = (Character) i.previous();
if( Character.isDigit(c)){
System.out.println(c + " is a digit");
list.remove(c);
}
}
System.out.println(list.size());
}
}
Here is the error message:
3
5 is a digit
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$ListItr.previous(AbstractList.java:386)
at mytrials.MyTrials.main(MyTrials.java:27)
Java Result: 1
What is the cause of this error and how can it be rectified.
Try
i.remove();
instead of
list.remove(c);
See here
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Use Iterator instead of the for-each(loop) construct when you need to:
Remove the current element.
The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.
Iterate over multiple collections in parallel.
Try to remove with your iterator :
i.remove(); // instead of list.remove(c);
The cause of the error is that the iterator's list was modified by using list.remove(c);.When a list is modified directly, the iterator becomes invalid, thus causing your error.
As Achintya Jha posted, you should use the iterator's remove function
list-iterator is a fail-fast iterator and throws an exception when a thread is trying to modify the list content while another thread is iterating it.
This might help
and this one
Related
I am trying to understand CopyOnWriteArrayList. Normally as for my understanding we cannot remove elements in for loop while we can remove in iterator if it exists..
public class HelloWorld {
public static void main(String arfs[]) {
CopyOnWriteArrayList<String> copyOnWrite = new CopyOnWriteArrayList<String> ();
copyOnWrite.add("One");
copyOnWrite.add("Two");
copyOnWrite.add("Three");
copyOnWrite.add("Four");
for(int i=0; i<copyOnWrite.size(); i++) {
copyOnWrite.remove(i);
}
}
}
Why this is not throwing an exception, as i am trying to remove an element from CopyOnWriteArrayList...
Iterator<String> itr = copyOnWrite.iterator();
while(itr.hasNext()) {
itr.remove();
}
But when using Iterator it is throwing an exception..normally this should be opposite right...
From docs regarding iterator of that collection
The iterator does NOT support the remove method.
see https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html#iterator()
Normally your expectation is correct for eg ArrayList - where removing item in enchanced FOR loop will throw ConcurrentModificationException and using iterator will not, but this is different implementation - thus different behavior.
No, the iterator is not supposed to make mutations, from the javadoc
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
"Element-changing operations on iterators themselves (remove, set, and add) are not supported. These methods throw UnsupportedOperationException."
In the first case it must be making a copy of the list upon mutation, which is the expected behavior for CopyOnWriteArrayList.
I have a very basic question.
I have created simple ArrayList and I am removing the item while iterating using for-each loop. It gives me java.util.ConcurrentModificationException because I can't remove an item while iterating but when I un-comment the if condition it works fine.
Please can anybody explain me how for-each works in this way.
ArrayList<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
list1.add("Good Evening");
for (String s : list1) {
//if (s.equals("World")) {
list1.remove(1);
//}
}
If I change it to list1.remove(2); or list1.remove(0); then also its working fine.
Note: This is sample code and I know it will work fine using Iterator. My sole purpose of this question is to know how method remove() works perfectly if condition is un-commented no matter what index you are removing from the list.
The list has a variable called modCount, which means "modification count". Whenever you call remove (or perform other structural modifications), it increments the modCount.
The iterator can't keep track of its position in the list if you are adding or removing elements without telling the iterator. So as a safety check, at the start of iteration, the iterator makes a note of the modCount, saving it as expectedModCount. When each item is read from the iterator, the iterator checks to make sure the modCount still equals the expected value, and throws an exception if it doesn't.
Usually, this will successfully cause the exception to be thrown if the list is unsafely modified during iteration. However, it's not sufficient in this case when the if statement is enabled. After your code has read "World", that item is removed, and so the list now contains ["Hello", Good Evening"]. The iterator is still at position 1 (which now contains "Good Evening") and when it tries to read the next item, it finds it has now reached the end of the list, so it doesn't bother to check the modCount. Hence, no exception.
Note the caveat in the ConcurrentModificationException documentation: "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."
Even if it doesn't happen to throw the exception in this case, the code is still wrong. To remove an element while iterating, you must use the iterator's own remove method:
for (Iterator<String> it = list1.iterator(); it.hasNext();) {
String s = it.next();
if (s.equals("World")) {
it.remove();
}
}
That way, the iterator knows that the list has changed and can still iterate correctly.
Alternatively, you can iterate from a temporary copy of the list:
for (String s : new ArrayList<>(list1)) {
if (s.equals("World")) {
list1.remove(...);
}
}
Although, in this simple case, you don't even need to do that; you can just write:
list1.remove("World");
You can also use an index-based removal. The drawback of this solution is that the list1.size() gets evaluated during every loop iteration. The positive thing is that removing an item from a List by its index is faster.
for (int i = 0; i < list1.size(); /* i incremented in loop body */) {
if ("World".equals(list1.get(i))) {
list1.remove(i);
}
else {
i++;
}
}
Use an Iterator and call remove():
Iterator<String> iter = list1.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
I want to know Different ways to remove element from Linked Hash Set. I tried following code
LinkedHashSet<String> lhs = new LinkedHashSet<String>();
for(int i=0;i<10;i++)
lhs.add(String.valueOf(i));
Iterator<String> it=lhs.iterator();
System.out.println("removed?=="+lhs.remove("1"));
while(it.hasNext())
{
System.out.println("lhs"+it.next());
}
i got following output
removed?==true
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(Unknown Source)
at java.util.LinkedHashMap$KeyIterator.next(Unknown Source)
at preac.chapter1.Start.main(Start.java:321)
What i miss? thanks in advance.
P.S I have also tried iterator.remove() method but got Illegal State Exception
EDIT
I just came to know i have to use iterator remove method. then what it is use of Link Hash Set remove method ? In which cases we should use this method?
Try to remove element using Iterator.remove like below,
LinkedHashSet<String> lhs = new LinkedHashSet<String>();
for (int i = 0; i < 10; i++) {
lhs.add(String.valueOf(i));
}
Iterator<String> it=lhs.iterator();
// System.out.println("removed?=="+lhs.remove("1"));
while(it.hasNext()) {
String value=it.next();
if("1".equals(value)){
it.remove();
}
else{
System.out.println("lhs "+value);// Print the other value except 1
}
}
System.out.println(lhs);// After remove see the result here.
You get the exception because the iterator realizes that you called remove after creating the iterator (using an internal modification counter).
Let's assume add and remove increment the modification counter by 1.
When the iterator is created, it sees a modification counter of 10.
However, when the iterator is first accessed, the modification counter is 11, due to the call to remove, hence the exception.
Switch the statements and it should be fine:
...
System.out.println("removed?=="+lhs.remove("1"));
Iterator<String> it=lhs.iterator();
...
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
#Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(String st:li){
if(st.equalsIgnoreCase("str3"))
li.remove("str3");
}
System.out.println(li);
}
When I run this code,I will throw a ConcurrentModificationException.
It looks as though when I remove the specified element from the list, the list does not know its size have been changed.
I'm wondering if this is a common problem with collections and removing elements?
I believe this is the purpose behind the Iterator.remove() method, to be able to remove an element from the collection while iterating.
For example:
Iterator<String> iter = li.iterator();
while(iter.hasNext()){
if(iter.next().equalsIgnoreCase("str3"))
iter.remove();
}
The Java 8 way to remove it from the List without Iterator is:
li.removeIf(<predicate>)
i.e.
List<String> li = new ArrayList<String>();
// ...
li.removeIf(st -> !st.equalsIgnoreCase("str3"));
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
Taken from http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html
yes people run into it -- the problem is you can't modify the list while iterating over it. I have used 2 alternatives in the past:
You can keep track of the indexes of the items you want to remove, and then remove them after you are done iterating.
Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.
those options assume you have to iterate over the list to find the elements to remove -- useful in cases where the list elements are complex objects with properties you might test on.
In your particular case, you dont even need to iterate, as you can just use removeAll. Look at the API here. There are also nifty methods like retainAll that discard everything that is not in the argument. You can use remove/retain-like methods whenever the objects in the list implement equals and hashcode properly. If you cannot rely on equals/hashcode to identify equality between instances in your app, you will have to do the removal yourself....
Try this (Java 8):
list.removeIf(condition);
You could make a copy of list you want to remove element from, directly in for-each loop. For me, that is the simpliest way. Something like this:
for (String stringIter : new ArrayList<String>(myList)) {
myList.remove(itemToRemove);
}
Hope that will help you..
I think it is worth mentioning the Java 8 version
#Test
public void testListCur() {
List<String> li = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
li.add("str" + i);
}
li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList());
System.out.println(li);
}
ArrayList has field modCount - count of collection modifications
When you invoke method iterator() creates new object Itr. It has field expectedModCount. expectedModCount field initialize by modCount value. When you invoke
li.remove("str3");
modCount increments. When do you try access to li via iterator
checks that expectedModCount == modCount
and if it is false throws ConcurrentModificationException
Hence if you get iterator and after collection modified - iterator is considered not valid and you cannot use it.
I think that best answer is from bigdev.de, but i would like to add something to it(like if the item is removed from a list, maybe you would like to log that somewhere or something):
List<String> list = new ArrayList<>();
list.removeIf(a -> {
boolean condition = a.equalsIgnoreCase("some condition");
if(condition)
logger.info("Item removed from the list: " + a);
return condition;
});
I got this problem and I think the easier way is the same with the second way that hvgotcodes gave.
Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.
#Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
List<String> finalLi = new ArrayList<String>();
for(String st:li){
if(st.equalsIgnoreCase("str3")){
// Do nothing
} else {
finalLi.add(st);
}
}
System.out.println(finalLi);
}
I looped a different way...
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(int i=0; i<li.size(); i++)
if(li.get(i).equalsIgnoreCase("str3"))
li.remove(i--);
System.out.println(li);
}
This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 3 years ago.
I was reading this "Freuqent Java concurrency problems" question and got confused by an answer talking about java.util.ConcurrentModificationException.
My understanding of the answer is that this can occur in a single-threaded program.
How or what conditions cause the following code to throw the exception?
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }
This snippet will always throw a ConcurrentModificationException.
The rule is the following: 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).
Note however that you are allowed to modify the list through the iterator (because then it is aware of the modification, and can take it into account) using the Iterator.remove or ListIterator.add.
From the docs:
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.
The word concurrent here refers to that you're modifying the list during traversal.
Because you are deleting from a list and iterating on it using a iterator at the same time.
See equivalent code using iterator.
import java.lang.*;
import java.util.*;
class Test{
public static void main(String[] argv){
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
Iterator<String> itr=list.iterator();
while(itr.hasNext()){
String a=itr.next();
list.remove(a);
}
}
}
Right code is
import java.lang.*;
import java.util.*;
class Test{
public static void main(String[] argv){
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
Iterator<String> itr=list.iterator();
while(itr.hasNext()){
itr.remove();
}
}
}
You are changing a list as you loop through it.
Here ConcurrentModificationException has nothing to do with threads.
Warning! The following example is here to show how it may be dangerous to use a collection as you change it. It's not what exactly happened in OP's case (looping through iterator and changing)
I think it would be easier to imagine what's wrong with it if you use an old-fashioned loop with a counter like this:
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (int i = 0; i < list.size(); i++) {
list.remove(i); //removes element at given index
}
Now, the first time i is 0, and 0th element is removed. The second time i is 1, so now 1st element is removed. But, what is now 1st, used to be 2nd, before the first removal. So, what used to be 1st, and now is 0th, will never be removed.