Reputation: 5417
Is it safe to remove multiple items from an ArrayList while iterating through it with an iterator?
Iterator<String> iterator = nameList.iterator();
while(iterator.hasNext()){
String s = iterator.next();
List<String> list = work(s);
for (String s1 : list) {
nameList.remove(s1);
}
}
The work()
method gives back a list of names that should be removed from the nameList, during the runtime of while loop.
Upvotes: 7
Views: 2097
Reputation: 7329
You can use Iterator.remove()
(as opposed to nameList.remove(s)
).
Iterator<String> iterator = nameList.iterator();
while(iterator.hasNext()){
String s = iterator.next();
iterator.remove();
}
Also consider nameList.clear()
and nameList.removeAll(elementsToRemove)
.
Iterators are generally invalid after any modification to their underlying collections, except via the iterator itself. - When I sort a List what happens to its iterators?
https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html
Upvotes: 0
Reputation: 816
You can implement your logic if you use a ListIterator which is fail-safe. Below is a basic example :
Set<String> removed = new HashSet<>();
ArrayList<String> nameList = new ArrayList<String>();
ListIterator<String> iterator = nameList.listIterator();
while(iterator.hasNext()){
String s = iterator.next();
if (!removed.contains(s)) {
removed.addAll(work(s));
}
}
nameList.removeAll(removed);
System.out.println(nameList);
With your logic, you have to account the performance. If performance is not a factor, you can go ahead and add/remove from a list through ListIterator.
Upvotes: 2
Reputation: 1365
As a previous answer said, removing an item from a iterated list is not safe. Here is a code that throws ConcurrentModificationException
:
List<String> list = new ArrayList<>(Arrays.asList("1", "2", "3"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
list.remove("1");
}
Upvotes: 0
Reputation: 394126
No, it's not safe, and can throw ConcurrentModificationException
. You can collect all the elements to be removed in a temporary List
, and then call list.removeAll(tmpList)
after the while loop to perform the removal.
Iterator<String> iterator = nameList.iterator();
List<String> removed = new ArrayList<>();
while(iterator.hasNext()){
String s = iterator.next();
removed.addAll(work(s));
}
list.removeAll(removed);
I realize this can be less efficient, since you might be calling work(s)
on String
s the should have been removed from the List
earlier. This can be improved by changing tempList
to a Set
, and only calling work(s)
for String
s not in the Set
:
Iterator<String> iterator = nameList.iterator();
Set<String> removed = new HashSet<>();
while(iterator.hasNext()){
String s = iterator.next();
if (!removed.contains(s)) {
removed.addAll(work(s));
}
}
list.removeAll(removed);
Upvotes: 12