AP Computer Science A study materials
AP Computer Science A study resources

ArrayList Removal While Iterating

AP Computer Science A · Put your knowledge to work in context.

All case studies

ArrayList Removal While Iterating

A student wants to remove all negative numbers from an ArrayList<Integer> nums and writes:

for (int i = 0; i < nums.size(); i++) {
    if (nums.get(i) < 0) {
        nums.remove(i);
    }
}

With nums = [-1, -2, 5, -3, 4], the result is [-2, 5, -3, 4] - the first element is removed but the second negative survives. The student tries an enhanced for-loop instead and gets a ConcurrentModificationException. A teammate suggests iterating backward.

1. Explain the index bug in the first loop using the specific input, and why the enhanced for-loop throws `ConcurrentModificationException`.

Read the worked answer

When remove(i) executes, elements after i shift left by one, and size() decreases. The loop then increments i, skipping the element that moved into slot i.

Trace on [-1, -2, 5, -3, 4]:

  • i=0: -1 < 0, remove → [-2, 5, -3, 4]. i becomes 1.
  • i=1: now nums.get(1) is 5, not -2. -2 was skipped.
  • i=2: -3 < 0, remove → [-2, 5, 4]. i becomes 3, which is size() - loop ends.

Result [-2, 5, 4] region still contains -2. The bug: after a removal, the next element shifts into the current index, but the loop advances past it.

The enhanced for-loop uses an Iterator; ArrayList.remove structurally modifies the list, so the iterator's next next() detects the change and throws ConcurrentModificationException. You cannot remove via the list while iterating with the for-each.

2. Give two correct fixes and state the tradeoff between them.

Read the worked answer

Fix 1 - iterate backward:

for (int i = nums.size() - 1; i >= 0; i--) {
    if (nums.get(i) < 0) {
        nums.remove(i);
    }
}

Removing index i shifts only elements above i, which have already been processed, so no element is skipped. Simple and safe.

Fix 2 - use an explicit Iterator:

Iterator<Integer> it = nums.iterator();
while (it.hasNext()) {
    if (it.next() < 0) {
        it.remove();
    }
}

Iterator.remove() is the sanctioned way to modify during iteration and avoids the exception.

Tradeoff: backward indexing is easy to read and needs no import, but it is O(n) removals each O(n) in the worst case (shifts), so O(n²). The Iterator version is also O(n²) for ArrayList but expresses intent clearly and is required if you must iterate forward. A third option, nums.removeIf(x -> x < 0), is O(n) and clearest when available. The judgment call is readability versus control; for a beginner, backward iteration is the least error-prone.