ArrayList Traversals

Same Loop Shapes as Arrays

For-each, indexed for, and while all work on an ArrayList — just with get(i) instead of [i], and .size() instead of .length:

// for-each — read-only pass
for (String log : logs) { System.out.println(log); }
// indexed
for (int i = 0; i < logs.size(); i++) { System.out.println(logs.get(i)); }

The Big Restriction: Don't Resize During a For-Each

Adding or removing elements from an ArrayList while a for-each loop is traversing it usually throws ConcurrentModificationException — but not always. Remove the second-to-last element and the loop can end silently instead, quietly skipping the last element rather than throwing anything. Either way, it's broken; never rely on the exception to catch this for you. If you need to add or remove while looping, use an indexed for or while loop instead.

Removing While Looping — The Careful Way

Removing an element shifts every later element down by one index. If you increment the loop index unconditionally after a removal, you skip checking the element that just got shifted into the spot you were on:

int i = 0;
while (i < logs.size())
{
    if (shouldRemove(logs.get(i)))
    {
        // don't increment i here — the next element just shifted into index i
        logs.remove(i);
    }
    else
    {
        i++; // only advance when nothing was removed this iteration
    }
}

Chaining Through a List of Objects

// assume RobotPart exists, with getName() — Ch.17 builds it out fully
ArrayList<RobotPart> parts = new ArrayList<RobotPart>();
// chain: get the object, then call a method on it
String firstName = parts.get(0).getName();

Removing Without the Careful Index Dance

Once interfaces and generics are covered (Ch.19), removeIf(condition) and the Iterator's own remove() do this same job in one call, without the manual index bookkeeping above — a preview worth knowing about, not required yet.

Common Pitfalls

  • Adding/removing inside a for-each loop. Usually throws ConcurrentModificationException, but can also silently skip an element instead — switch to an indexed for or while loop if the list's size needs to change mid-traversal.
  • Incrementing the index unconditionally after a remove. This skips the element that shifted into the just-vacated slot — only advance the index when you didn't remove anything that pass.
  • Using <= against .size(). Same off-by-one risk as arrays — the last valid index is size() - 1.

Key Takeaways

  • ArrayList supports the same loop shapes as arrays, using get(i)/.size() instead of [i]/.length.
  • Never add or remove elements from an ArrayList while traversing it with a for-each loop — it usually throws, but can also fail silently instead.
  • When removing elements in an indexed/while loop, only advance the index on iterations where nothing was removed.
  • removeIf()/Iterator.remove() (Ch.19) do this more directly once interfaces are covered.

Derived from csawesome-2026: unit-4-data-collections/4.09-arraylist-traversals.md (CSA 4.9)