In Java, if we remove items from a List while iterating it, it will throw java.util.ConcurrentModificationException. This article shows a few ways to solve it.
Table of contents
- 1. java.util.ConcurrentModificationException
- 2. Java 8 Collection#removeIf
- 3. ListIterator example
- 4. Filter and Collect example
- 5. References
P.S Tested with Java 11.
1. java.util.ConcurrentModificationException
If we remove an item from an ArrayList while iterating it, the list.remove(s) will throws java.util.ConcurrentModificationException.
package com.mkyong.basic;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class IteratorApp1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for (String s : list) {
if ("A".equals(s)) {
// throws java.util.ConcurrentModificationException
list.remove(s);
}
}
System.out.println(list);
}
}
Output
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
at com.mkyong.basic.IteratorApp.main(IteratorApp.java:16)
2. Java 8 Collection#removeIf
In Java 8, we can use the Collection#removeIf API to remove items from a List while iterating it.
2.1 removeIf examples
package com.mkyong.basic;
import java.util.ArrayList;
import java.util.List;
public class IteratorApp2A {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
// remove if item is "A"
list.removeIf("A"::equals);
System.out.println(list);
}
}
Output
[B, C]
Another removeIf example.
package com.mkyong.basic;
import java.util.ArrayList;
import java.util.List;
public class IteratorApp2B {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
// remove if item is 1 or 3
list.removeIf(x -> x == 1 || x == 3);
System.out.println(list);
}
}
Output
[2]
2.2 removeIf uses Iterator
Review the Java 8 Collection#removeIf method signature, and the API uses Iterator to remove the item while iterating it.
package java.util;
public interface Collection<E> extends Iterable<E> {
//...
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
//...
}
3. ListIterator example
Before Java 8, we can use ListIterator to remove the items from a List while iterating it.
package com.mkyong.basic;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class IteratorApp3 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
ListIterator<String> iter = list.listIterator();
while(iter.hasNext()){
if("A".equals(iter.next())){
iter.remove();
}
}
System.out.println(list);
}
}
Output
[B, C]
4. Filter and Collect example
4.1 We also can create a new List to store the filtered result.
package com.mkyong.basic;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class IteratorApp4A {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
List<String> result = new ArrayList<>();
for (String s : list) {
if (!"A".equals(s)) {
result.add(s);
}
}
System.out.println(result);
}
}
Output
[B, C]
4.2 In Java 8, we can use a stream to filter and collect.
package com.mkyong.basic;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class IteratorApp4B {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
// Java 8
List<String> result = list
.stream()
.filter(x -> !"A".equals(x))
.collect(Collectors.toList());
System.out.println(result);
}
}
Output
[B, C]
I deeply love your website and your articles. they are awesome.
Thank you for sharing.
I believe the second approach that you said, is incorrect. because if your watch the ArrayList source code, it overrides the removeIf() method and it again has checked the modCount to detect the concurrent modification.
Thanks. I prefer solution from pt. 3