Article start
Java Programming: From Zero to Enterprise
3. Core APIs & I/O

28. Iterator: Safe Collection Traversal

Traversing and modifying collections simultaneously without breaking them.

February 22, 2026·69

[!NOTE] Have you ever tried to loop through an ArrayList of 10 items using a standard for-each loop, and attempted to .remove() an item inside the loop if it met a certain condition?

If you do this, your application will violently crash with a ConcurrentModificationException.

Java does not allow you to modify the size of a collection while an advanced for-each loop is actively traversing it. It breaks the internal memory pointer logic of the loop!

The Iterator Object

To safely loop through a collection while actively deleting elements from it, you must use an Iterator.

An Iterator is an object that can be used to loop through collections, like ArrayList and HashSet. It acts like a cursor hovering right before the first element.

import java.util.ArrayList;
import java.util.Iterator;

public class Main {
  public static void main(String[] args) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();
    numbers.add(12);
    numbers.add(8);
    numbers.add(2);
    numbers.add(23);
    
    // 1. We summon an Iterator linked directly to our collection
    Iterator<Integer> it = numbers.iterator();
    
    // 2. We use a while-loop. .hasNext() checks if there is another item available!
    while(it.hasNext()) {
      // 3. .next() physically grabs the item and moves the cursor forward
      Integer i = it.next();
      
      // 4. If the number is less than 10, we delete it safely!
      if(i < 10) {
        it.remove(); // Safely deletes 8 and 2!
      }
    }
    
    System.out.println(numbers); // Output: [12, 23]
  }
}

When to use standard loops vs Iterators?

  • Use a standard for loop if modifying sizes and you don't mind manually adjusting the i counter backwards.
  • Use a clean for-each loop if you are just Reading data or printing values sequentially. This is 95% of use cases.
  • Use a while(iterator.hasNext()) if you are executing intensive filter checks and actively deleting invalid data.

[!TIP] With the introduction of Java 8 Streams, explicit Iterator writing has become much rarer. You can now use numbers.removeIf(i -> i < 10); in a single elegant line of code! But understanding the Iterator mechanics is a mandatory interview question.

Safe Removal While Traversing

Iterators matter because they coordinate traversal and removal through one cursor. When you remove directly from a collection during a for-each loop, the loop's internal cursor and the collection's structure disagree.

Iterator Removal

Iterator<String> iterator = names.iterator();

while (iterator.hasNext()) {
    String name = iterator.next();
    if (name.isBlank()) {
        iterator.remove();
    }
}

Modern Alternative: removeIf

names.removeIf(name -> name.isBlank());

removeIf is concise for simple filtering. Iterator is still useful when the removal logic is more involved or when you need to understand how traversal works internally.

Common Mistakes

  • Calling iterator.remove() before calling next().
  • Mixing direct collection removal with iterator traversal.
  • Using iterator code for simple cases where removeIf is clearer.
  • Forgetting that fail-fast behavior helps expose unsafe modification bugs.

Mini Practice

Create a list of marks and remove all marks below 40 using an Iterator. Then solve the same problem using removeIf.

Practice Lab: Remove Failed Marks Safely

Remove elements during traversal without causing concurrent modification problems.

  1. Create an ArrayList<Integer> of marks.
  2. Use an Iterator<Integer>.
  3. Remove all marks below 40 using iterator.remove().
  4. Print the remaining marks.
  5. Solve the same problem with removeIf(mark -> mark < 40).

Goal: Learn both explicit iterator removal and modern predicate-based removal.

Revision Checkpoint

  • Iterator: Cursor for traversing collections.
  • hasNext(): Checks whether another item exists.
  • next(): Returns current item and advances.
  • remove(): Safely removes the current item after next().
  • removeIf: Cleaner for simple predicate-based removal.

Before the quiz: Explain why direct removal inside for-each is unsafe.