i know that we shouldn't modify the ArrayList during iteration.
But i'm using Iterator to iterate over list and iterator.remove() to remove the element but still results in ConcurrentModification Exception.
My program is not multithreaded.
I've many arraylist [class contains it and i'm processing many array of objects]
for(int i=0;i<obj.length;i++)
{
if(k==i) continue;
it = obj[i].arraylist.iterator();
while(it.hasNext()){
value = it.next();
if(condn) {
it.remove();
obj[k].arraylist.add(value);
//k and i are not same
}
}
}
"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."
You can remove objects but not add new ones during the iteration, that's why you get that ConcurrentModificationException.
http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html
Edit:
You can also check:
if(k==i || obj[i].arraylist == obj[k].arraylist) continue;
You can only modify the List during iteration using it variable.
Related
I am executing a database query, and as result I get a HashMap. I want to iterate through all the results, but I infinitely add the first item from the result to the arraylist.
QueryResult result=engine.query(query,params);
while(result.iterator().hasNext()) {
HashMap res= (HashMap)result.iterator().next();
Node node=(Node)res.get("n");
results.add(new BusyProfile(node));
}
How to iterate through each object and why do I have infinite loop? Thanks!
Everytime you call result.iterator(), a new Iterator is created, pointing to the first item.
So create it before your loop:
Iterator<?> it = result.iterator();
while (it.hasNext()) {
HashMap res = (HashMap)it.next();
//...
}
You are overwriting your iterator! When result.iterator() is called, you create your iterator but on each iteration, it's creating a new one and it continues to point to the beginning - causing the infinite loop.
What you need to do in this case is save the iterator and then use it to move through the collection.
QueryResult result = engine.query(query,params);
//Save iterator
Iterator i = result.iterator();
while(i.hasNext()) {
HashMap res = (HashMap)i.next();
Node node = (Node)res.get("n");
results.add(new BusyProfile(node));
}
Before you can access a collection through an iterator, you must
obtain one. Each of the collection classes provides an iterator( )
method that returns an iterator to the start of the collection. By
using this iterator object, you can access each element in the
collection, one element at a time.
In general, to use an iterator to cycle through the contents of a
collection, follow these steps −
Obtain an iterator to the start of the collection by calling the
collection's iterator( ) method.
Set up a loop that makes a call to hasNext( ). Have the loop iterate
as long as hasNext( ) returns true.
Within the loop, obtain each element by calling next( ).
There is a quick tutorial here:
https://www.tutorialspoint.com/java/java_using_iterator.htm
All answers posted before mine explained that result.iterator() will instantiate a new iterator each time it is invoked.
And it makes not sense to create an iterator during each iteration for the same iterator that you are iterating with : while(result.iterator().hasNext()) {
.It is right.
Beyond this misuse of the Iterator, you should read the javadoc of the class you are using. It may often help you to create a more effective code.
According to the javadoc of org.neo4j.ogm.session.result.QueryResult, the
QueryResultclass implements the Iterable interface in this way Iterable<Map<String,Object>>.
So instead of doing thing more complicated than required, just use an enhanced for.
It would produce a shorter and more readable code.
Besides, using the more restricted scope for a variable is better as it prevents to use it unsuitably.
With the enhanced for, you don't need any longer to declare the iterator before the loop.
It will be used in the compiled class (as enhanced for uses under the hood an iterator) but it will be restricted to the scope of the loop.
So you should really consider this way :
QueryResult result = engine.query(query,params);
for (Map<String,Object> currentMap : result) {
Node node = (Node) currentMap.get("n");
results.add(new BusyProfile(node));
}
You should call the iterator() method once and then store (and use) the returned value.
Reuse the Iterator
Iterator i = result.iterator();
if(i.hasNext()) {
HashMap res= (HashMap)i.next();
Node node=(Node)res.get("n");
results.add(new BusyProfile(node));
}
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 am getting a java.util.ConcurrentModificationException in this code and can't seem to understand why, or fix it.
In the BO I have this (privileges is an arraylist inside the BO)
public void setPrivilegename(String privilegename) {
this.privileges.add(privilegename);
}
List<PrivilegeObjectBO> arraylist = new ArrayList<PrivilegeObjectBO>();if (rs != null) {
while (rs.next()) {
for (BO bo : arraylist) {
if (bo.getRolepkey()==rs.getInt("ROLE_PKEY")) {
bo.setPrivilegename(rs.getString("SP.NAME"));
}else{
BO newobj = new BO();
newobj.setRolepriviledgepkey(rs.getInt("PRIVILEGE_PKEY"));
newobj.setProticolpkey(protocol);
newobj.setPrivilegename(rs.getString("SP.NAME"));
newobj.setRolepkey(rs.getInt("SRP.ROLE_PKEY"));
arraylist.add(newobj);
}
}
}
}
As per ArrayList 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.
for (BO bo : arraylist)
Above for-each loop gets Iterator for the list and
arraylist.add(newobj);
You are trying to modify the list without using iterators own methods, which results in ConcurrentModificationException
Here is SO discussion on possible solutions.
In java, you will always get a ConcurrentModificationException when you modify the Collection while you are iterating over it.
Possible solution: use a temporary Collection for added or deleted items, and add or delete those items after the iteration is done.
You cannot iterate over ArrayList and add elements to it at the same time with foreach.
Use iterator, like this:
Iterator<PrivilegeObjectBO> iterator = arraylist.iterator();
while (iterator.hasNext()) {
...
}
Others have already pointed out that add-ing to an ArrayList while iterating over it is disallowed.
But to solve your problem anyway, it looks like you need to iterate over the entire list before attempting to add to it, because it your loop appears to be checking to see if anything in the list matches your row to avoid duplicates. In this case you don't want to add to the list while iterating over it because you don't know whether the list has a duplicate until the end.
So just iterate through and check to see if a match is found:
List<PrivilegeObjectBO> arraylist = new ArrayList<PrivilegeObjectBO>();
if (rs != null) {
while (rs.next()) {
boolean found = false;
for (BO bo : arraylist) {
if (bo.getRolepkey() == rs.getInt("ROLE_PKEY")) {
bo.setPrivilegename(rs.getString("SP.NAME"));
found = true;
}
}
if (!found) {
BO newobj = new BO();
newobj.setRolepriviledgepkey(rs.getInt("PRIVILEGE_PKEY"));
newobj.setProticolpkey(protocol);
newobj.setPrivilegename(rs.getString("SP.NAME"));
newobj.setRolepkey(rs.getInt("SRP.ROLE_PKEY"));
arraylist.add(newobj);
}
}
}
Unless you really do want to add a new BO for every non-matching BO already in the list...
Maybe you can take a look at Collections.synchronizedList(List<?>) static method.
It should return a thread safe List from the List object given, and you should not get the exception anymore.
Otherwise, you could try (if applicable) to set the method that accesses to the list synchronized, by adding the keyword synchronized in the method declaration.
I have a list I need to iterate over and delete certain items. I can't use an iterator because I need to call methods for each item (such as ls.getStatus()) which doesn't work with an iterator. If ls.getStatus() == 0 I need to delete that item. How can I avoid the ConcurrentModificationException?
for (MyList ls : list) {
if (ls.getStatus() == 0) {
ls.run();
list.remove();
} else {
ls.create();
}
}
Thanks
Why don't you think you can use an iterator?
Iterator<MyList> i = list.iterator();
while (i.hasNext()) {
MyList ls = i.next();
//... all your other code which uses ls...
i.remove();
}
This approach is also likely to be faster, since using iterator.remove() avoids having to search for the item in the list which is necessary with list.remove(item).
You can use an iterator, but only by abandoning the enhanced for loop:
for (Iterator<MyList> iterator = list.iterator(); iterator.hasNext(); ) {
MyList ls = iterator.next();
if (ls.getStatus() == 0) {
lo.run(zo);
iterator.remove();
} else {
ls.create();
}
}
Of course, that assumes that list refers to a type which supports the remove operation.
In case your iterator does not support remove operation you could use following algorithm:
In first step you can iterate over list creating list of indices of elements to be deleted. Next step would be iterating over list of indices backward and deleting elements by index.
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);
}