UNIT 4: DATA COLLECTIONS · TOPIC 4.9
4.9 ArrayList Traversals
Same two loop styles as arrays, with one extra hazard: modifying the list's size while looping over it.
What you need to know
- Standard:
for (int i = 0; i < list.size(); i++)withlist.get(i). Enhanced:for (String s : list). - Removing during a forward loop skips elements. After
remove(i), the next element shifts into index i, then i++ jumps past it. - Fixes: after removing, do
i--(or don't increment); or traverse backward withfor (int i = list.size() - 1; i >= 0; i--), where removals don't affect unvisited indices. - Never add or remove inside an enhanced for loop — it throws
ConcurrentModificationException. - Enhanced for over an ArrayList of objects lets you call mutators on each element (the reference is shared); over
ArrayList<Integer>, assigning to the loop variable does nothing to the list. - The loop condition
i < list.size()is re-evaluated each iteration, so a shrinking list shortens the loop.
Worked example
ArrayList<Integer> a = new ArrayList<Integer>();
// a = [4, 4, 7, 4]
// BUGGY: remove all 4s
for (int i = 0; i < a.size(); i++)
{
if (a.get(i) == 4) a.remove(i);
}
// result: [4, 7] — second 4 was skipped
// CORRECT: backward
for (int i = a.size() - 1; i >= 0; i--)
{
if (a.get(i) == 4) a.remove(i);
}
// result: [7]
Trace it yourself
Step through with the buttons, or use the ← → keys. Changed variables are highlighted.
Exam tip: If a question removes elements in a forward loop, trace it literally — the answer usually has "leftover" elements that were skipped. If asked for the correct version, pick the backward loop or the one with
i-- after remove.Going deeper
The nuance, edge cases, and connections that turn a 3 into a 5.
- The removal bug, step by step: list
[2, 2, 5], remove all 2s with a forward loop. i=0: get(0)=2, remove →[2, 5]. i=1: get(1)=5, no. Done. Result[2, 5]— the second 2 shifted into index 0 and was never examined. - Fix A — backward:
for (int i = list.size() - 1; i >= 0; i--). Removing at i shifts elements after i, which you've already visited. Unvisited elements (before i) keep their indices. - Fix B — don't advance after removing: use a while loop with manual increment, or
i--right afterremove(i)in a for loop. Either way, the shifted-in element is re-examined. - Enhanced for + structural change = ConcurrentModificationException. Adding or removing inside
for (T x : list)throws at run time (not compile time). Calling mutators on the elements is fine; changing the list's size is not. - Adding in a forward loop: inserting at i pushes the current element to i+1, so i++ lands on it again — potential infinite loop if you insert every time. Insert, then
i++extra to skip. - size() is re-evaluated each iteration. A shrinking list ends the loop sooner; a growing list extends it. This is different from a for loop over an array, where length is fixed.
- Object elements:
for (Student s : roster) s.setGrade(…)changes the objects in the list — the reference is shared.for (Integer n : nums) n = 0;changes nothing — n is a copy.
Mistakes that cost points
- Forward-loop removal. Skips the element after each removal. The exam asks for the buggy output; trace it literally.
- Removing inside an enhanced for. Run-time exception.
- Caching size() before the loop. If the list shrinks, you go out of bounds.
Practice questions
Written in the style of the real exam. Try each one before revealing the answer.
Q1 What is the contents of
list after the following code, where list starts as [1, 2, 2, 3, 2]?
for (int i = 0; i < list.size(); i++)
{
if (list.get(i) == 2)
{
list.remove(i);
}
}Show answer
Answer: B. i=1 removes the first 2 → [1, 2, 3, 2]; i=2 is 3 (the second 2 shifted to index 1 and was skipped); i=3 removes the last 2 → [1, 2, 3].
Q2 Which of the following correctly removes every element equal to
target from an ArrayList<Integer> nums?Show answer
Answer: B. Backward traversal handles removals safely. A throws ConcurrentModificationException; C skips adjacent matches; D goes out of bounds.
Key vocabulary
- ConcurrentModificationException
- the error from modifying an ArrayList inside an enhanced for loop
- Backward traversal
- looping from size - 1 down to 0, safe for removals