Java – How to remove items from a List while iterating?
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