Skip to main content

Java Collections

Iterator

Complete lesson for Iterator using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with Java OOP and Collections where relevant.

L1

Basics — Iterator

Section: Java Collections. Iterator, ListIterator, fail-fast, forEachRemaining, and ConcurrentModificationException.

Iterator is a cursor

  • Iterable.iterator() returns an Iterator. Enhanced for is compiled to this loop.
  • hasNext() / next() are the core. remove() removes the last element returned by next() — optional operation.
  • Calling next() without hasNext() throws NoSuchElementException. Calling remove() twice without next() throws IllegalStateException.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorBasics {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("keep");
        list.add("drop");
        list.add("keep");
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            if (it.next().equals("drop")) {
                it.remove();
            }
        }
        System.out.println(list);
    }
}

Iterator vs ListIterator vs for-each

APIDirectionCan set/add?Safe remove?
IteratorForwardNoremove() only
ListIteratorBoth (hasPrevious)set / addYes
for-eachForwardNoNo — CME if you mutate
forEachRemaining (Java 8)Rest of cursorNoDepends on iterator

ListIterator extras

  • list.listIterator() or listIterator(index). nextIndex() / previousIndex() support algorithms that need positions.
  • set(e) replaces the last element returned. add(e) inserts before the implicit next.
L2

Advanced — Iterator

Fail-fast, weakly consistent, Spliterator

  • ArrayList / HashMap iterators increment modCount. A mismatch throws ConcurrentModificationException — even on one thread.
  • This is not a lock. Two threads mutating a HashMap can still corrupt it without always seeing CME.
  • ConcurrentHashMap / ConcurrentLinkedQueue iterators are weakly consistent: they reflect some but not necessarily all concurrent updates, and they do not throw CME.
  • CopyOnWriteArrayList iterator is a snapshot — remove on the iterator is unsupported.
  • Streams use Spliterator (splitable iterator) for parallel decomposition. iterator() and spliterator() both come from Iterable.
L3

Tricky Interview Points

Q1) How do you remove while iterating a List?

Answer Use Iterator.remove, ListIterator.remove, removeIf, or iterate indexes backward. Do not list.remove inside for-each.

Q2) What is fail-fast?

Answer The iterator detects that the collection’s modCount changed (structural change) and throws ConcurrentModificationException.

Q3) Iterator vs ListIterator?

Answer ListIterator is list-only, bidirectional, and can set/add. Iterator is the general Collection cursor.

Q4) Why does for-each throw CME when you add?

Answer for-each uses an Iterator. add is a structural change not done through that iterator.

Q5) Can you iterate a Map with Iterator?

Answer Yes — map.entrySet().iterator(), or keySet()/values(). Directly on Map there is no iterator() because Map is not a Collection.

Q6) Is ConcurrentModificationException guaranteed?

Answer No. It is fail-fast best effort. ConcurrentHashMap will not throw it for typical concurrent writes.

L4

Simple Programs

ListIterator reverse print and set

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorDemo {
    public static void main(String[] args) {
        List<String> words = new ArrayList<>();
        words.add("one");
        words.add("two");
        words.add("three");
        ListIterator<String> it = words.listIterator(words.size());
        while (it.hasPrevious()) {
            String w = it.previous();
            if (w.equals("two")) it.set("TWO");
            System.out.println(w);
        }
        System.out.println(words);
    }
}
L5

Problem Solving Tricks

  • removeIf is clearer than a manual iterator for predicate deletes.
  • When teaching CME, mutate in for-each on purpose once so the stack trace is familiar.
  • For maps, iterate entrySet — not keys then get.
  • Iterator.forEachRemaining(Consumer) is handy after you already consumed a prefix.
  • Do not store an iterator and reuse it after the collection changes.
L6

Practice Programs List

  1. Delete every string shorter than 3 using an Iterator.
  2. Use ListIterator to insert "x" before each "a".
  3. Reproduce CME, then fix the same loop.
  4. Iterate a HashMap with entrySet().iterator() and remove keys starting with _.
  5. Write a method that returns an Iterator over 1..n without storing the whole list (custom Iterator).