# AP® Computer Science A 4.9 ArrayList Traversals

Source: https://lockincs.com/ap-csa/unit-4/4-9-arraylist-traversals/  
Last reviewed against the College Board Course and Exam Description (CED): 2026-11-12  
CED codes: 4.9.A, 4.9.A.1, 4.9.A.2, 4.9.A.3, 4.9.A.4

Traversing an ArrayList means using loops (or recursion) to access all of its elements or an ordered sequence of them. Removing elements during a traversal shifts the later elements left, so you need a special technique, such as not increasing the index after a removal or traversing backward, to avoid skipping elements. An index outside 0 to size() - 1 throws an IndexOutOfBoundsException, and changing the size inside an enhanced for loop can throw a ConcurrentModificationException.

## What you will learn

- 4.9.A Develop code used to traverse the elements of an ArrayList and determine the results of these traversals.

## 1\. Traversing an ArrayList

Traversing an `ArrayList` means using iteration (loops) or recursive statements to access all of the elements, or an ordered sequence of them 4.9.A.1. The loops look like array loops with two changes: `size()` instead of `length`, and `get(i)` instead of `[i]`.

```
ArrayList<Integer> steps = new ArrayList<Integer>();
steps.add(5200);
steps.add(8100);
steps.add(7400);

for (int i = 0; i < steps.size(); i++)          // indexed for
{
    System.out.print(steps.get(i) + " ");
}
System.out.println();

int total = 0;
for (int s : steps)                             // enhanced for (unboxing to int)
{
    total += s;
}
System.out.println("Total: " + total);

int k = steps.size() - 1;                       // while, backward
while (k >= 0)
{
    System.out.print(steps.get(k) + " ");
    k--;
}
System.out.println();
```

Output:

```
5200 8100 7400 
Total: 20700
7400 8100 5200 
```

To change elements, use `set` in an indexed loop (assigning to the enhanced for loop variable changes nothing, as with arrays):

```
ArrayList<String> tags = new ArrayList<String>();
tags.add("java");
tags.add("loop");

for (int i = 0; i < tags.size(); i++)
{
    tags.set(i, "#" + tags.get(i));
}
System.out.println(tags);
```

Output:

```
[#java, #loop]
```

**Preview:** a traversal can also be recursive: a method handles one element and then calls itself for the rest. Recursion is covered in topic 4.16; here is a small example to trace.

```
public static void printFrom(ArrayList<String> list, int index)
{
    if (index < list.size())
    {
        System.out.print(list.get(index) + " ");
        printFrom(list, index + 1);
    }
}
```

```
ArrayList<String> stops = new ArrayList<String>();
stops.add("Park");
stops.add("Museum");
stops.add("Harbor");
printFrom(stops, 0);
System.out.println();
```

Output:

```
Park Museum Harbor 
```

## 2\. Removing during a traversal: the skipping bug

Deleting elements during a traversal of an `ArrayList` requires special techniques to avoid skipping elements 4.9.A.2. The reason: `remove(i)` shifts every later element one place left, so the next element moves into index `i`. If the loop then does `i++`, that element is never checked.

Goal: remove every score below 50.

```
ArrayList<Integer> scores = new ArrayList<Integer>();
scores.add(72);
scores.add(40);
scores.add(35);
scores.add(90);

for (int i = 0; i < scores.size(); i++)
{
    if (scores.get(i) < 50)
    {
        scores.remove(i);
    }
}
System.out.println(scores);
```

Output:

```
[72, 35, 90]
```

35 survived. Trace it:

| `i` | list at the start of the pass | `get(i)` | action |
| --- | --- | --- | --- |
| 0 | \[72, 40, 35, 90\] | 72 | keep |
| 1 | \[72, 40, 35, 90\] | 40 | remove(1); 35 shifts to index 1 |
| 2 | \[72, 35, 90\] | 90 | keep (35, now at index 1, was skipped) |

## 3\. Two safe ways to remove

**Technique 1: only move forward when nothing was removed.**

```
ArrayList<Integer> scores = new ArrayList<Integer>();
scores.add(72);
scores.add(40);
scores.add(35);
scores.add(90);

int i = 0;
while (i < scores.size())
{
    if (scores.get(i) < 50)
    {
        scores.remove(i);       // the next element is now at index i: check it next
    }
    else
    {
        i++;
    }
}
System.out.println(scores);
```

Output:

```
[72, 90]
```

(The same idea in a `for` loop is to write `i--;` right after `remove(i)`, so the `i++` in the header cancels it out.)

**Technique 2: traverse backward.** Removing at index `i` only shifts elements **after** `i`, and a backward loop has already checked those.

```
ArrayList<Integer> scores = new ArrayList<Integer>();
scores.add(72);
scores.add(40);
scores.add(35);
scores.add(90);

for (int i = scores.size() - 1; i >= 0; i--)
{
    if (scores.get(i) < 50)
    {
        scores.remove(i);
    }
}
System.out.println(scores);
```

Output:

```
[72, 90]
```

| `i` | list at the start of the pass | `get(i)` | action |
| --- | --- | --- | --- |
| 3 | \[72, 40, 35, 90\] | 90 | keep |
| 2 | \[72, 40, 35, 90\] | 35 | remove(2) |
| 1 | \[72, 40, 90\] | 40 | remove(1) |
| 0 | \[72, 90\] | 72 | keep |

## 4\. Adding during a traversal

Adding has the opposite shift. `add(i, obj)` pushes the current element to index `i + 1`, so a forward loop meets it again on the next pass. Goal: put a “warm up” before every “run”.

```
ArrayList<String> plan = new ArrayList<String>();
plan.add("run");
plan.add("rest");
plan.add("run");

for (int i = 0; i < plan.size(); i++)
{
    if (plan.get(i).equals("run"))
    {
        plan.add(i, "warm up");
        i++;                    // skip past the "run" that just moved to i + 1
    }
}
System.out.println(plan);
```

Output:

```
[warm up, run, rest, warm up, run]
```

Without the extra `i++`, the loop would find the same “run” at index `i + 1`, insert again, and keep going until the program runs out of memory.

## 5\. IndexOutOfBoundsException

Attempting to access an index value outside the range 0 to `size() - 1` results in an `IndexOutOfBoundsException` 4.9.A.3. Two ways it happens in traversals:

```
ArrayList<String> names = new ArrayList<String>();
names.add("Ada");
names.add("Ben");

for (int i = 0; i <= names.size(); i++)        // <= is one pass too many
{
    System.out.println(names.get(i));
}
```

Output:

```
Ada
Ben
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 2 out of bounds for length 2
```

Saving the size in a variable before a loop that removes elements also fails, because the list gets shorter but the saved number does not:

```
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(4);
nums.add(-1);
nums.add(6);

int n = nums.size();                            // 3, and it stays 3
for (int i = 0; i < n; i++)
{
    if (nums.get(i) < 0)
    {
        nums.remove(i);
    }
}
System.out.println(nums);
```

Output:

```
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 2 out of bounds for length 2
```

| `i` | list at the start of the pass | `get(i)` | action |
| --- | --- | --- | --- |
| 0 | \[4, -1, 6\] | 4 | keep |
| 1 | \[4, -1, 6\] | \-1 | remove(1); the size is now 2 |
| 2 | \[4, 6\] | `get(2)` | exception: `n` is still 3, but index 2 no longer exists |

Write `i < nums.size()` in the condition so the loop sees the current size (and combine it with a technique from section 3).

## 6\. ConcurrentModificationException

Changing the size of an `ArrayList` while traversing it with an enhanced `for` loop can result in a `ConcurrentModificationException` 4.9.A.4. So when you use an enhanced `for` loop on an `ArrayList`, you should not add or remove elements 4.9.A.4.

```
ArrayList<String> cart = new ArrayList<String>();
cart.add("apple");
cart.add("soda");
cart.add("bread");
cart.add("soda");

for (String item : cart)
{
    if (item.equals("soda"))
    {
        cart.remove(1);
    }
}
System.out.println(cart);
```

Output:

```
Exception in thread "main" java.util.ConcurrentModificationException
```

The code compiles; the exception happens when the loop tries to move to the next element after the list has changed size. Adding inside an enhanced `for` loop fails the same way. Use one of the indexed techniques from section 3 instead.

| Loop type | Read elements | Replace with `set` | Remove or add |
| --- | --- | --- | --- |
| indexed `for` / `while` | yes | yes | yes, with a special technique |
| enhanced `for` | yes | no (no index) | no: `ConcurrentModificationException` |

## Common mix-ups

- Not true: A normal forward for loop with remove(i) removes every match. After remove(i), the next element slides into index i, and then i++ jumps past it. Two matches in a row means one is skipped.
- Not true: You can remove from a list inside an enhanced for loop if you are careful. Changing the size of an ArrayList while traversing it with an enhanced for loop can throw a ConcurrentModificationException. Do not add or remove inside an enhanced for loop.
- Not true: Saving the size before the loop makes removing safe. The saved size becomes too big after the first removal, so the loop reaches indexes that no longer exist and throws an IndexOutOfBoundsException. Use list.size() in the condition.

## In 30 seconds

- Traverse an ArrayList with for or while loops (get(i), size()), an enhanced for loop, or recursion.
- Deleting during a traversal needs a special technique: only increase i when nothing was removed, or traverse backward.
- Inserting during a forward traversal shifts the current element right, so skip past it or the loop may run forever.
- Indexes outside 0 to size() - 1 throw an IndexOutOfBoundsException.
- Changing the size inside an enhanced for loop can throw a ConcurrentModificationException, so never add or remove there.

## Checkpoint: 5 practice questions

### Question 1

Consider the following code segment. What is printed as a result of executing the code segment?

```java
ArrayList<String> w = new ArrayList<String>();
w.add("cat");
w.add("cow");
w.add("dog");
w.add("cub");
w.add("emu");
for (int i = 0; i < w.size(); i++)
{
    if (w.get(i).substring(0, 1).equals("c"))
    {
        w.remove(i);
    }
}
System.out.println(w);
```

- A. [dog, emu]
- B. [cow, dog, emu]
- C. [cow, dog, cub, emu]
- D. [dog, cub, emu]

**Answer: B.** When "cat" is removed at index 0, "cow" shifts into index 0, but `i` moves on to 1, so "cow" is skipped. Then "dog" is kept and "cub" is removed at index 2. The result is [cow, dog, emu]. "[dog, emu]" is what a correct removal would give; the other two miss that "cub" is checked and removed.

### Question 2

Consider the following code segment. What is the result of executing the code segment?

```java
ArrayList<Integer> vals = new ArrayList<Integer>();
vals.add(3);
vals.add(8);
vals.add(5);
vals.add(6);
for (int v : vals)
{
    if (v > 4)
    {
        vals.add(v - 4);
    }
}
System.out.println(vals);
```

- A. [3, 8, 5, 6, 4, 1, 2] is printed
- B. [3, 8, 5, 6, 4] is printed
- C. The loop never ends
- D. A `ConcurrentModificationException` is thrown

**Answer: D.** The code changes the size of the list (with `add`) while traversing it with an enhanced for loop. When the loop moves on after adding 4, a `ConcurrentModificationException` is thrown. It does not finish with the added values, and it does not loop forever; to add while traversing, use an indexed loop.

### Question 3

Consider the following code segment. What is the result of executing the code segment?

```java
ArrayList<Integer> a = new ArrayList<Integer>();
a.add(10);
a.add(20);
a.add(30);
int total = 0;
for (int i = a.size(); i > 0; i--)
{
    total += a.get(i);
}
System.out.println(total);
```

- A. An `IndexOutOfBoundsException` is thrown
- B. 60 is printed
- C. 50 is printed
- D. A `ConcurrentModificationException` is thrown

**Answer: A.** The loop starts with `i = a.size()`, which is 3. The valid indexes are 0 to 2, so `a.get(3)` throws an `IndexOutOfBoundsException` on the first pass. "60" assumes all elements are added, "50" adds indexes 1 and 2, and a `ConcurrentModificationException` needs the size to change during an enhanced for loop, which does not happen here.

### Question 4

The method `removeNegatives` is intended to remove every negative value from `list`. Which of the following can replace `/* missing code */` so that the method works as intended for every list?

```java
public static void removeNegatives(ArrayList<Integer> list)
{
    /* missing code */
}
```

- A. `for (int i = 0; i < list.size(); i++) { if (list.get(i) < 0) { list.remove(i); } }`
- B. `for (int i = list.size() - 1; i >= 0; i--) { if (list.get(i) < 0) { list.remove(i); } }`
- C. `for (int i = list.size(); i >= 0; i--) { if (list.get(i) < 0) { list.remove(i); } }`
- D. `int n = list.size(); for (int i = 0; i < n; i++) { if (list.get(i) < 0) { list.remove(i); } }`

**Answer: B.** Traversing backward means each removal only shifts elements that were already checked, so nothing is skipped. The forward loop skips the element after each removal (for example, it leaves -2 in [-1, -2, 3]); starting at `list.size()` throws an `IndexOutOfBoundsException` on the first pass; and the saved size `n` becomes too large after a removal, which can lead to an `IndexOutOfBoundsException` (for example with [-1, 5]) and also skips elements.

### Question 5

Consider the following code segment. What is printed as a result of executing the code segment?

```java
ArrayList<String> s = new ArrayList<String>();
s.add("red");
s.add("blue");
s.add("green");
for (int i = 0; i < s.size(); i += 2)
{
    s.add(i, "x");
}
System.out.println(s);
```

- A. [x, red, blue, green]
- B. [x, red, x, blue, green]
- C. [x, red, x, blue, x, green]
- D. Nothing; the loop never ends

**Answer: C.** Each `add(i, "x")` inserts before the element at `i` and shifts it right, and `i += 2` jumps past that element. With `i` = 0, 2 and 4, an "x" goes before red, blue and green, and the loop stops when `i` is 6 and the size is 6. The first two options stop too early, and the loop does end because `i` grows by 2 while the size grows by 1.

## Questions students ask

**How do you remove elements from an ArrayList while looping?**

Use an indexed loop and only increase the index when you do not remove, or loop backward from size() - 1 to 0. Never remove inside an enhanced for loop.

**Why does my loop skip elements when I remove from an ArrayList?**

remove(i) moves the next element into index i. Your i++ then moves past it without checking it. Do not increase i after a removal.

**What causes a ConcurrentModificationException?**

Changing the size of an ArrayList, with add or remove, while traversing it with an enhanced for loop.

**Can I use an enhanced for loop with an ArrayList?**

Yes, to read every element in order, for example to sum or count. Do not add or remove elements in it, and you cannot replace elements through the loop variable.

---

© LockInCS, licensed CC BY-NC-ND 4.0. AP® is a trademark registered by the College Board, which is not affiliated with, and does not endorse, this website.
