How to avoid ConcurrentModificationException while iterating this collection? - java

I need to iterate over a collection of items & sometimes add to that collection at the same time. However, incase I add while iterating then I just start the iteration from fresh by breaking out of iteration loop & restarting iteration from beginning. However this leads to
ConcurrentModificationException. [code below]
List<Integer> collection = new ArrayList<>();
for (Integer lobId: collection) {
..
if (someCondition) {
collection.add(something);
break;
}
}
How could I possibly do something like above avoiding ConcurrentModificationException?
Would it be correct to simply use an Array instead of ArrayList to avoid this exception ?
Is there any type of specialized collection for this ?
--
Edit:
I dont want to create a new copy for this arraylist because I'm repeating this entire iteration process multiple times unless some requirement is completed. Creating a new copy each time would bring in some extra overhead, which I would like to avoid if somehow possible.
Also if possible I would like to maintain a sorted order & unique values in that collection. Is there anything that is ready to use in any library? Otherwise I could sort it at the end of iteration process & remove duplicates. That will also do fine for me.

Use another collection for the additions and combine them at the end.
List<Integer> collection = new ArrayList<>();
collection.add(...)
...
List<Integer> tempCollection = new ArrayList<>();
for (Integer lobId: collection ) {
..
if (someCondition) {
tempCollection.add(something);
break;
}
}
collection.addAll(tempCollection);

This code cannot lead to ConcurrentModificationException because after you add an element you break the loop and dont use iterator anymore

if I understand you right, you want to iterate over the list , if some condition , you want to break the iteration , and an item and start fresh .
In the case do this:
List<Integer> collection = new ArrayList<>();
boolean flag = false;
Integer item =
for (Integer lobId: collection) {
..
if (someCondition) {
flag = true;
item = something;
break;
}
}
if (flag){
collection.add(item);
}
if someone else is going to change the list outside out loop - you will need to sync those access - read iterator thread safe , and use the other answers here like copying the list or some other copy on write

ConcurrentModificationException basically means that you're iterating over a Collection with one iterator (albeit implicitly defined by your enhanced for loop) and invalidating it on the fly by changing the Collection itself.
You can avoid this by doing the modifications via the sameiterator:
List<Integer> collection = new ArrayList<>();
ListIterator<Integer> iter = collection.listIterator();
while (iter.hasNext()) {
Integer currVal = iter.next();
if (someCondition) {
iter.add(something); // Note the addition is done on iter
break;
}
}

Don't use for each, use the good old
for(int i=0; i<collection.size();i++)

Related

Using only nested loops, if-else statements, and ArrayList methods, how do I locate and remove duplicate values in an ArrayList (Java)? [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
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 TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here

Removing elements from array in java throws exception [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
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 TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here

Iterator inside Iterator ConcurrentModificationException

I am having the following problem:
Given an ArrayList (let's call it list), how can I "double-iterate" through it without getting ConcurrentModificationException?
Here's what I've tried:
iterator out = list.iterator();
iterator in;
while(out.hasNext()){
...
in = list.iterator();
while(in.hasNext()){
...
if(something)
in.remove();
}
You can't do that. A potential solution might be to mark objects to be removed, for example:
final List<Foo> toRemove = new ArrayList<>();
for (Foo a : list)
{
for (Foo b : list)
{
if (something)
{
toRemove.add(b);
}
}
}
list.removeAll(toRemove);
You may need some additional checks to see that the object isn't already marked for removal. It's impossible to say given how vague your example is.
You are trying to modify an iterator. It will give you concurrentModification exception.
In java 8 you can easily remove it using
list.removeIf(someCondition)
Try this link java8 collections
The Iterator instance provided through a call to List#iterator method preserves a count scalar allowing to detect external changes to the Collection container.
When an element is removed from the collection by any other mean than going through the same Iterator#remove(T) call, the count is not updated behind the scenes.
Therefore when you request for the #next() element through the iterator instance, the count is checked against an expected value and if both values does not match (since an element has been removed through another iterator) a ConcurrentModificationException is thrown (even though you may be working in a single threaded environment).
The solution whould be, as #Michael stated, to keep track of the container elements that should be removed then perform a bulk delete:
Collection<Object> temp = new ArrayList<>();
iterator out = list.iterator();
iterator in;
while (out.hasNext()) {
// ...
in = list.iterator();
while (in.hasNext()) {
// ...
if(something)
// just mark the element for deletion
temp.add(in.next());
}
}
// delete all the obsolete elements
list.removeAll(temp);
In collection once iterator creator If you try to modify the content not through same iterator it will throw concurrent exception.If you required some special kind of iterator then you can go ahead and implement your own.

Removing values in an arraylist that DO NOT match a value

I am having some trouble with removing values that do not match a given value. At the moment I am copying over values to a new list and trying to clear the original list - but this is inefficient.
This is my code:
int size = list.size();
ArrayList<String> newList;
int count = 0;
newList = new ArrayList<>();
for (int i=0; i<list.size(); i++){
if(list.get(i).getForename().equals(forename)){
newList.add(i, list);
}
}
list.clear();
Is there a way where I can just remove an item in the arraylist if it does NOT match the name?
EDIT:
It works but then I might need a copy, as if I select a another name from the dropdown it will be referring to the old one
Thanks
A first thought would be to iterate on the list and as soon as you find an item not matching the value, you remove it. But it will create a Concurrent modification exception, as you iterate on list while trying to remove elements in it.
An other, still not efficient would be to iterate on the list, keep track of the indexes to remove, and after iterating on the list, remove them.
ArrayList<Integer> indexList = new ArrayList<Integer>();
for(int i = 0; i<list.size(); i++){
if(!list.get(i).getForename().equals(forename)){
indexList.add(i);
}
for(Integer index : indexList){
list.remove(index);
}
indexList.clear();
Please not that this is not really efficient too, but maybe you were looking for a way to delete from the same list.
A simple solution is
while (list.contains(value)) {
list.remove(list.indexOf(value));
}
Depending on what you want, you might want to use streams instead (seems to be what you actually want, since you don't really seem to want to delete elements in your list):
newList = list.stream()
.filter(e -> getForename().equals(forename))
.collect(Collectors.toList());
or to perform your action what you might want to do:
list.stream()
.filter(e -> getForename().equals(forename))
.forEach(person -> doStuff(person));
Another way would be using iterators to avoid conflicts with modifications during iteration:
ListIterator iterator = list.listIterator();
while(iterator.hasNext()){
if(!iterator.getNext().getForename().equals(forename))
iterator.remove();
}
EDIT: Since OP can't use lambdas and streams (because of Java-version), here is what nearly happens for the second stream (the forEach). I am not using the proper interfaces, since OP can't do so either. The difference to streams is, that they also might split this into several threads and hence would be faster (especially on multi-core processors and big lists):
interface Consumer<T>{ //this is normally given by the JAVA 8 API (which has one more default method)
void accept(T t);
}
Consumer<YourObject> doIt = new Consumer<YourObject>(){ //This is what the lambda expression actually does
#Override
public void accept(YourObject e) {
doStuff(e);
}
};
for(YourObject element : list){ //since JAVA 1.5. Alternativ your old for-loop with element=list.get(i);
if(!element.getForename().equals(forename)) //the filter written in easy
continue;
doIt.accept(element); //You could also use a method or expressions instead in this context.
//doStuff(element); //What actually the upper stream does.
}
You might want to look at the oracle tutorial (this chapter) to get a feeling, when this design is appropriate https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html (I have a strong feeling, you might want to use it).
Assuming your List contains String objects the following should be what you are looking for:
for (Iterator<String> it = list.iterator(); it.hasNext()){
String foreName = it.next();
if(forName != null && foreName.equals(forename)){
it.remove();
}
}
try
for (int i=0; i<list.size();){
if(!list.get(i).getForename().equals(forename)){
list.remove(i);
}
else {
i++;
}
}

Modifying a set during iteration java

I'm looking to make a recursive method iterative.
I have a list of Objects I want to iterate over, and then check their subobjects.
Recursive:
doFunction(Object)
while(iterator.hasNext())
{
//doStuff
doFunction(Object.subObjects);
}
I want to change it to something like this
doFunction(Object)
iIterator = hashSet.iterator();
while(Iterator.hasNext()
{
//doStuff
hashSet.addAll(Object.subObjects);
}
Sorry for the poor psuedo code, but basically I want to iterate over subobjects while appending new objects to the end of the list to check.
I could do this using a list, and do something like
while(list.size() > 0)
{
//doStuff
list.addAll(Object.subObjects);
}
But I would really like to not add duplicate subObjects.
Of course I could just check whether list.contains(each subObject) before I added It.
But I would love to use a Set to accomplish that cleaner.
So Basically is there anyway to append to a set while Iterating over it, or is there an easier way to make a List act like a set rather than manually checking .contains()?
Any comments are appreciated.
Thanks
I would use two data structures --- a queue (e.g. ArrayDeque) for storing objects whose subobjects are to be visited, and a set (e.g. HashSet) for storing all visited objects without duplication.
Set visited = new HashSet(); // all visited objects
Queue next = new ArrayDeque(); // objects whose subobjects are to be visited
// NOTE: At all times, the objects in "next" are contained in "visited"
// add the first object
visited.add(obj);
Object nextObject = obj;
while (nextObject != null)
{
// do stuff to nextObject
for (Object o : nextObject.subobjects)
{
boolean fresh = visited.add(o);
if (fresh)
{
next.add(o);
}
}
nextObject = next.poll(); // removes the next object to visit, null if empty
}
// Now, "visited" contains all the visited objects
NOTES:
ArrayDeque is a space-efficient queue. It is implemented as a cyclic array, which means you use less space than a List that keeps growing when you add elements.
"boolean fresh = visited.add(o)" combines "boolean fresh = !visited.contains(o)" and "if (fresh) visited.add(o)".
I think your problem is inherently a problem that needs to be solved via a List. If you think about it, your Set version of the solution is just converting the items into a List then operating on that.
Of course, List.contains() is a slow operation in comparison to Set.contains(), so it may be worth coming up with a hybrid if speed is a concern:
while(list.size() > 0)
{
//doStuff
for each subObject
{
if (!set.contains(subObject))
{
list.add(subObject);
set.add(subObject)
}
}
}
This solution is fast and also conceptually sound - the Set can be thought of as a list of all items seen, whereas the List is a queue of items to work on. It does take up more memory than using a List alone, though.
If you do not use a List, the iterator will throw an exception as soon as you read from it after modifying the set. I would recommend using a List and enforcing insertion limits, then using ListIterator as that will allow you to modify the list while iterating over it.
HashSet nextObjects = new HashSet();
HashSet currentObjects = new HashSet(firstObject.subObjects);
while(currentObjects.size() > 0)
{
Iterator iter = currentObjects.iterator();
while(iter.hasNext())
{
//doStuff
nextObjects.add(subobjects);
}
currentObjects = nextObjects;
nextObjects = new HashSet();
}
I think something like this will do what I want, I'm not concerned that the first Set contains duplicates, only that the subObjects may point to the same objects.
Use more than one set and do it in "rounds":
/* very pseudo-code */
doFunction(Object o) {
Set processed = new HashSet();
Set toProcess = new HashSet();
Set processNext = new HashSet();
toProcess.add(o);
while (toProcess.size() > 0) {
for(it = toProcess.iterator(); it.hasNext();) {
Object o = it.next();
doStuff(o);
processNext.addAll(o.subObjects);
}
processed.addAll(toProcess);
toProcess = processNext;
toProcess.removeAll(processed);
processNext = new HashSet();
}
}
Why not create an additional set that contains the entire set of objects? You can use that for lookups.

Categories