Removing multiple items from an ArrayList during an iterator

Is it safe to delete multiple elements from an ArrayList, 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 returns a list of names that should be removed from nameList during the execution of the while loop.

+5
source share
4 answers

No, this is not safe, and may throw a ConcurrentModificationException . You can collect all the items that you want to remove in the temporary List , and then call list.removeAll(tmpList) after the while loop to perform the deletion.

 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 understand that this may be less efficient, since you could call work(s) on a String , it should have been removed from the List earlier. This can be improved by changing tempList to Set and calling only work(s) for String not in 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); 
+10
source

You can implement your logic if you use ListIterator, which is fault tolerant. The following 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 consider performance. If performance is not a factor, you can continue and add / remove from the list via ListIterator.

+2
source

Of course, but I would use a regular loop for length, not for an iterator ...

for(int c = 0; c < list.length; ++c) list.removeAt(c)

Or just while(list.length > 0) list.removeat(0);

There may also be a subclass list and add a removeRange implementation, such as splice.

0
source

As stated in the previous answer, removing an item from a re-list is unsafe. Here is the code that throws a 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"); } 
0
source

Source: https://habr.com/ru/post/1275359/


All Articles