Fundamentals 9 min read

8 Reliable Ways to Remove Elements from a Java List (And Why Some Fail)

This article examines eight common techniques for deleting elements from a Java List, explains why certain loop‑based approaches cause errors or unexpected results, and highlights the three reliable methods—including reverse for‑loops, iterator.remove, and Stream filtering—that work correctly.

macrozheng
macrozheng
macrozheng
8 Reliable Ways to Remove Elements from a Java List (And Why Some Fail)

During a recent conversation a developer struggled to delete elements from a Java List and encountered runtime errors. The article analyzes why this happens and presents several ways to perform the deletion correctly.

Problem

Given the following list:

public List<String> initList = Arrays.asList("张三", "李四", "周一", "刘四", "李强", "李白");

How can we remove all elements whose name starts with "李"?

Methods

We analyze several possible implementations.

1. Ordinary for loop deletion (unreliable)

/**
 * 普通 for 循环删除
 */
@Test
public void remove1() {
    List<String> list = new ArrayList(initList);
    for (int i = 0; i < list.size(); i++) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

Output: [张三, 周一, 刘四, 李白] The loop uses list.size() that changes during iteration, causing the loop to terminate early and leave some elements undeleted.

2. Ordinary for loop with size variable (throws exception)

/**
 * 普通 for 循环删除(size提出变量)
 */
@Test
public void remove2() {
    List<String> list = new ArrayList(initList);
    int size = list.size();
    for (int i = 0; i < size; i++) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

Result: an IndexOutOfBoundsException because size is fixed while the actual list shrinks.

3. Ordinary for loop reverse order (reliable)

/**
 * 普通 for 循环倒序删除
 */
@Test
public void remove3() {
    List<String> list = new ArrayList(initList);
    for (int i = list.size() - 1; i > 0; i--) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

Output: [张三, 周一, 刘四] Iterating backwards prevents index shifting issues, making this approach safe.

4. Enhanced for loop deletion (throws exception)

/**
 * 增强 for 循环删除
 */
@Test
public void remove3() {
    List<String> list = new ArrayList(initList);
    for (String element : list) {
        if (element.startsWith("李")) {
            list.remove(element);
        }
    }
    System.out.println(list);
}

Result: java.util.ConcurrentModificationException because the underlying iterator detects concurrent modification.

5. Iterator loop with iterator.remove() (reliable)

/**
 * 迭代器循环删除(iterator.remove)
 */
@Test
public void remove4() {
    List<String> list = new ArrayList(initList);
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
        String str = iterator.next();
        if (str.contains("李")) {
            iterator.remove();
        }
    }
    System.out.println(list);
}

Output: [张三, 周一, 刘四] The iterator’s remove method synchronizes the expected modification count, avoiding the concurrent‑modification error.

6. Iterator loop with list.remove (throws exception)

/**
 * 迭代器循环删除(list.remove)
 */
@Test
public void remove5() {
    List<String> list = new ArrayList(initList);
    for (Iterator<String> ite = list.iterator(); ite.hasNext(); ) {
        String str = ite.next();
        if (str.contains("李")) {
            list.remove(str);
        }
    }
    System.out.println(list);
}

Result: another ConcurrentModificationException because removal is performed on the list rather than through the iterator.

7. Collection forEach deletion (throws exception)

/**
 * list.forEach 删除
 */
@Test
public void remove6() {
    List<String> list = new ArrayList(initList);
    list.forEach((e) -> {
        if (e.contains("李")) {
            list.remove(e);
        }
    });
    System.out.println(list);
}

Result: ConcurrentModificationException because forEach internally uses an iterator.

8. Stream filter (reliable)

/**
 * stream filter 过滤
 */
@Test
public void remove7() {
    List<String> list = new ArrayList(initList);
    list = list.stream().filter(e -> !e.startsWith("李")).collect(Collectors.toList());
    System.out.println(list);
}

Output: [张三, 周一, 刘四] This approach leverages the Stream API to create a new list without the unwanted elements, offering concise and safe removal.

Summary

The article presents eight ways to delete elements from a Java List. Only three methods are reliable: reverse‑order for loops, iterator‑based removal, and Stream filtering. The other approaches either miss elements or raise ConcurrentModificationException, illustrating common pitfalls for developers.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaListStreamIteratorCollectionConcurrentModificationException/loop
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.