Skip to content

JAVA FOUNDATIONS · JAVA 17

Java Iterator: remove matching elements safely

Remove failing marks through an ArrayList iterator and understand why direct structural changes during iteration are a problem.

Forsk Coding School learning resources · Updated 2026-10-26

What you will learn

  • Use hasNext and next in the correct order
  • Remove the last returned element through the iterator
  • Recognize fixed-size and unmodifiable list limitations

Before you start: List, ArrayList, loops and conditions.

Choose how the traversal will change the data

A loop that reads a collection and a loop that removes elements have different needs. An enhanced for loop is convenient for reading. When using an ArrayList iterator to remove selected items, perform the removal through that iterator. Calling list.remove directly while its iterator is active can invalidate the traversal and may trigger ConcurrentModificationException.

Despite that exception's name, this issue can occur in one thread. It is about structural modification outside the iterator's expected path, not proof that another thread is involved. Fail-fast behaviour is a bug-detection aid, not a synchronization mechanism and not a guaranteed way to enforce correctness.

Follow the iterator state

hasNext asks whether there is another element. next returns it and advances the iterator. remove then removes the element most recently returned by next. You cannot call remove before the first next, or call it twice for one returned element. The example keeps these steps next to each other so their relationship is visible.

The source values are wrapped in a new ArrayList. Arrays.asList alone would provide a fixed-size list, whose iterator cannot perform this removal. Other iterators may also omit optional mutation support. Know the concrete collection's contract when choosing a traversal that modifies it.

Test adjacent matches and empty input

The marks contain two failing values next to each other. That case catches an index-loop mistake in which removing an item shifts the next one left and the increment skips it. Iterator removal handles the traversal position for this ArrayList, so both 35 and 39 are removed. The passing values 40 and 75 remain in their original order.

Also try an empty list, a list with no matches and a list where every element matches. Each case should finish without an invalid next call. If the caller needs the original list preserved, copy it before mutating or build a separate result collection. Safe traversal does not decide whether mutating shared data is appropriate for your application.

Run the worked example

Save as Main.java. Run javac Main.java, then java Main.

Main.java
import java.util.*;
public class Main {
    public static void main(String[] args) {
        List<Integer> marks = new ArrayList<>(Arrays.asList(35, 39, 40, 75));
        Iterator<Integer> iterator = marks.iterator();
        while (iterator.hasNext()) {
            int mark = iterator.next();
            if (mark < 40) iterator.remove();
        }
        System.out.println(marks);
    }
}

Expected result

[40, 75]
  1. Each next call returns one mark and advances the traversal.
  2. remove is used only for the failing mark just returned.
  3. Two adjacent failing marks are both removed without skipping either.

Common mistakes to check

  • Do not call next without first checking that an element exists.
  • Call iterator.remove rather than directly removing from this ArrayList during its iteration.
  • Check whether the chosen collection supports removal.

Try it yourself

Remove every negative value from the mutable list {-2, -1, 0, 4, -3}. Preserve the order of remaining values.

Give me a hint

Check the value returned by next and call remove when it is less than zero.

Compare with one working solution
Main.java
import java.util.*;
public class Main {
    public static void main(String[] args) {
        List<Integer> values = new ArrayList<>(Arrays.asList(-2, -1, 0, 4, -3));
        Iterator<Integer> iterator = values.iterator();
        while (iterator.hasNext()) {
            if (iterator.next() < 0) iterator.remove();
        }
        System.out.println(values);
    }
}

Expected result

[0, 4]

Quick check

Choose an answer, then check the explanation. Your answer stays in this page and is not saved as a student record.

When is iterator.remove valid for this iterator?

Keep learning

Explain the result in your own words, change one input and predict the new output. For additional structured assignments, explore the workbook sample before requesting the full pack.

Explore the practice workbook

Reference documentation

Use the official reference to check language details. The explanations, examples and exercises on this page are written for this learning resource.