Traversing an ArrayList means using a loop or recursion to visit its elements in order. You can use an indexed for loop, a while loop, or an enhanced for loop, but you cannot safely add or remove elements during an enhanced for loop. For AP Computer Science A, choose the traversal style based on whether you only need to read elements or also modify the list.
Why This Matters for the AP Computer Science A Exam
ArrayList traversal shows up in both multiple-choice and free-response code writing. In multiple-choice, you often trace a loop to predict output or spot why a segment throws an exception or skips elements. In free-response, you write methods that analyze and manipulate an ArrayList of objects, and these methods frequently ask you to insert or remove elements, which means you have to adjust the loop counter so you do not skip or overshoot positions.
The skills tied to this topic include writing code that uses ArrayList traversals, explaining why a segment will not work as intended and fixing it, and describing what a segment of code does. Being fluent with both indexed loops and enhanced for loops gives you flexibility on whichever question type appears.

Key Takeaways
- Traversing an ArrayList uses iteration or recursion to access all or part of its elements in order.
- An indexed
forloop orwhileloop usesget(index)and runs while the index is less thansize(). - An enhanced
forloop reads each element in order but cannot safely add or remove elements. - Accessing an index outside
0tosize() - 1throws anIndexOutOfBoundsException. - Adding or removing during an enhanced
forloop traversal can throw aConcurrentModificationException. - Removing during an indexed loop shifts later elements left, so you must adjust the counter to avoid skipping elements.
Core Concepts
Ways to Traverse an ArrayList
You have a few standard ways to move through an ArrayList. Each visits elements in order, but they differ in how much control you get.
An indexed for loop or a while loop uses the index directly. You call get(i) to read an element and run the loop while i < list.size(). This gives you full control, including the ability to modify elements with set or to remove elements when you handle the index carefully.
An enhanced for loop (also called a for-each loop) reads a copy of each element in order without using an index. It is cleaner for read-only work, but you do not have the index, and you should not change the list's size inside it.
Recursion can also traverse an ArrayList by processing one element and then calling the method again on the rest. This is another form of repetition you may see in tracing questions.
Index Range and Out-of-Bounds Access
Valid indices for an ArrayList run from 0 to size() - 1. Trying to read or write an index outside that range throws an IndexOutOfBoundsException. A common mistake is starting an index loop at size() instead of size() - 1, or letting the loop condition run one step too far.
Index Shifting After Removal
When you remove an element at index i, every element after it shifts left by one position, and the size drops by one. The element that used to be at i + 1 is now at i. If your loop then increments to i + 1, you jump over that shifted element and skip it.
Two reliable fixes for an indexed loop:
- Loop backwards from
size() - 1down to0. Removals only affect indices you have already passed, so nothing gets skipped. - After removing at index
i, do not increment. Decrementi(or skip the increment) so the loop rechecks the position that the shifted element now occupies.
Inserting an element also shifts elements, but to the right, so the same care with the counter applies.
Why Enhanced For Loops Cannot Modify Size
An enhanced for loop is built for steady, read-only passes. If you add or remove elements during one, Java may throw a ConcurrentModificationException because the loop can no longer trust its position in the list. When you need to insert or delete during a traversal, switch to an indexed loop or collect the changes and apply them after the loop ends.
Code Examples
Enhanced For Loop: Clean Read-Only Traversal
</>Javaimport java.util.ArrayList; public class EnhancedForDemo { public static void main(String[] args) { ArrayList<String> fruits = new ArrayList<String>(); fruits.add("apple"); fruits.add("banana"); fruits.add("cherry"); fruits.add("date"); // Enhanced for loop is ideal for read-only traversal for (String fruit : fruits) { System.out.println(fruit + " has " + fruit.length() + " letters"); } // This would risk a ConcurrentModificationException: /* for (String fruit : fruits) { if (fruit.equals("banana")) { fruits.remove(fruit); // do not modify size here } } */ } }
Use an enhanced for loop when you only need to look at each element. The syntax is clean and there is no index to manage.
Indexed For Loop: Full Control with set
</>Javaimport java.util.ArrayList; public class TraditionalForDemo { public static void main(String[] args) { ArrayList<Integer> grades = new ArrayList<Integer>(); grades.add(85); grades.add(92); grades.add(78); grades.add(96); grades.add(73); for (int i = 0; i < grades.size(); i++) { int grade = grades.get(i); // set replaces an element without changing the size, so it is safe if (grade < 80) { grades.set(i, grade + 5); } } System.out.println("Final grades: " + grades); } }
An indexed loop gives you the position, which you need for operations like set. Because set does not change the size, it never causes index shifting.
The Wrong Way to Remove Elements
</>Javaimport java.util.ArrayList; public class RemovalMistake { public static void main(String[] args) { ArrayList<String> words = new ArrayList<String>(); words.add("hello"); words.add("remove"); words.add("world"); words.add("remove"); words.add("java"); // BUG: removing during a forward loop skips elements for (int i = 0; i < words.size(); i++) { if (words.get(i).equals("remove")) { words.remove(i); // the next element shifts down to index i, // but i increments, so that element is skipped } } System.out.println("After (buggy): " + words); // Not all "remove" elements are gone } }
When you remove at index i, the next element slides to i, but the loop moves to i + 1 and skips it.
Two Safe Ways to Remove Elements
</>Javaimport java.util.ArrayList; public class SafeRemoval { public static void main(String[] args) { ArrayList<String> words = new ArrayList<String>(); words.add("hello"); words.add("remove"); words.add("world"); words.add("remove"); words.add("java"); // Method 1: loop backwards so removals do not affect upcoming indices for (int i = words.size() - 1; i >= 0; i--) { if (words.get(i).equals("remove")) { words.remove(i); } } System.out.println("After backwards removal: " + words); // Reset for the second approach words.clear(); words.add("keep"); words.add("delete"); words.add("keep"); words.add("delete"); // Method 2: decrement i after removing so the shifted element is rechecked for (int i = 0; i < words.size(); i++) { if (words.get(i).equals("delete")) { words.remove(i); i--; } } System.out.println("After index adjustment: " + words); } }
Both methods avoid skipping. The backwards loop is often easier to reason about because you never have to adjust the counter mid-loop.
Building a New ArrayList During Traversal
</>Javaimport java.util.ArrayList; public class FilteringDemo { public static void main(String[] args) { ArrayList<Integer> allScores = new ArrayList<Integer>(); allScores.add(95); allScores.add(67); allScores.add(88); allScores.add(72); allScores.add(91); allScores.add(55); ArrayList<Integer> passing = new ArrayList<Integer>(); ArrayList<Integer> failing = new ArrayList<Integer>(); // Reading the original list and writing to new lists is always safe for (Integer score : allScores) { if (score >= 70) { passing.add(score); } else { failing.add(score); } } System.out.println("Passing: " + passing); System.out.println("Failing: " + failing); } }
Writing into new lists while reading the original is a clean way to filter without touching the list you are traversing.
Common Errors and Debugging
ConcurrentModificationException
This happens when you change an ArrayList's size during an enhanced for loop traversal.
</>CodeException in thread "main" java.util.ConcurrentModificationException
The usual cause is calling add or remove on the list inside an enhanced for loop. The fix is to switch to an indexed loop for the modification, or collect the changes and apply them after the loop finishes.
Index Shifting Bugs
These are quiet bugs where elements get skipped because the list shrank during a forward loop.
</>Java// looks fine, but skips elements for (int i = 0; i < list.size(); i++) { if (someCondition) { list.remove(i); // shifts elements left, but i still increments } }
Fix it with backwards iteration, or by decrementing i after a removal.
Off-by-One Errors in Backwards Loops
</>Java// Wrong: starts at size() instead of size() - 1 for (int i = list.size(); i >= 0; i--) { System.out.println(list.get(i)); // IndexOutOfBoundsException }
Valid indices run from 0 to size() - 1. Start a backwards loop at size() - 1, continue while i >= 0, and decrement with i--.
Practice Problems
Problem 1: Safe Element Removal
Write a method that removes all strings shorter than 4 characters from an ArrayList of strings without skipping any element.
</>Javaimport java.util.ArrayList; public class SafeRemovalPractice { // Backwards iteration (recommended) public static void removeShortStrings(ArrayList<String> words) { for (int i = words.size() - 1; i >= 0; i--) { if (words.get(i).length() < 4) { words.remove(i); } } } public static void main(String[] args) { ArrayList<String> testWords = new ArrayList<String>(); testWords.add("cat"); testWords.add("elephant"); testWords.add("no"); testWords.add("programming"); testWords.add("hi"); testWords.add("world"); System.out.println("Before: " + testWords); removeShortStrings(testWords); System.out.println("After: " + testWords); } }
Backwards iteration is a reliable choice because removals only touch indices you have already passed.
Problem 2: Data Processing with Indices
Write a method that replaces each element of an ArrayList of integers with the running sum up to that position. Print the index and new value for each element.
</>Javaimport java.util.ArrayList; public class RunningSumDemo { public static void calculateRunningSum(ArrayList<Integer> numbers) { int runningTotal = 0; for (int i = 0; i < numbers.size(); i++) { runningTotal += numbers.get(i); System.out.println("Index " + i + " -> " + runningTotal); numbers.set(i, runningTotal); } } public static void main(String[] args) { ArrayList<Integer> values = new ArrayList<Integer>(); values.add(5); values.add(3); values.add(8); values.add(2); values.add(7); System.out.println("Original: " + values); calculateRunningSum(values); System.out.println("Final: " + values); } }
This uses set to modify elements safely, since it does not change the list's size.
Problem 3: Traversal Method Comparison
Write two methods that return the index of the largest element in an ArrayList of integers, one using an indexed for loop and one using an enhanced for loop with manual index tracking.
</>Javaimport java.util.ArrayList; public class TraversalComparison { // Indexed loop: direct index access public static int findMaxIndexTraditional(ArrayList<Integer> numbers) { if (numbers.isEmpty()) return -1; int maxIndex = 0; for (int i = 1; i < numbers.size(); i++) { if (numbers.get(i) > numbers.get(maxIndex)) { maxIndex = i; } } return maxIndex; } // Enhanced loop: track the index yourself public static int findMaxIndexEnhanced(ArrayList<Integer> numbers) { if (numbers.isEmpty()) return -1; int maxIndex = 0; int currentIndex = 0; int maxValue = numbers.get(0); for (Integer value : numbers) { if (value > maxValue) { maxValue = value; maxIndex = currentIndex; } currentIndex++; } return maxIndex; } public static void main(String[] args) { ArrayList<Integer> testNumbers = new ArrayList<Integer>(); testNumbers.add(15); testNumbers.add(8); testNumbers.add(23); testNumbers.add(42); testNumbers.add(16); testNumbers.add(31); System.out.println("Numbers: " + testNumbers); System.out.println("Indexed result: " + findMaxIndexTraditional(testNumbers)); System.out.println("Enhanced result: " + findMaxIndexEnhanced(testNumbers)); } }
The enhanced loop needs a separate counter because it does not give you the index directly. The indexed loop has the position built in.
How to Use This on the AP Computer Science A Exam
Code Tracing
When you trace an ArrayList loop, write the list contents and the index next to each iteration. After any remove, redraw the list so you can see which element shifted into the open spot. This makes skipped-element bugs obvious instead of hidden.
Free Response
When a free-response method asks you to insert or remove elements, decide up front how you will protect the loop counter. Loop backwards for removals, or decrement the index after a removal in a forward loop. State the valid index range to yourself, 0 to size() - 1, before you write any get or remove call.
Common Trap
If a question shows an enhanced for loop that adds or removes from the same list, the expected answer is usually a runtime exception, not a clean result. Watch for that pattern.
Common Misconceptions
- Enhanced
forloops cannot edit the list's size. Reading and printing is fine, but adding or removing during one risks aConcurrentModificationException. - Using
setis not the same as adding or removing.setreplaces a value in place and does not change the size, so it is safe in any loop type. - Removing an element does not leave a gap. The list closes up, shifting later elements left and reducing the size, which is exactly why forward removal loops skip elements.
- Valid indices stop at
size() - 1. Looping tosize()or starting a backwards loop atsize()throws anIndexOutOfBoundsException. - A buggy removal loop does not always crash. It often runs without error but quietly leaves some elements behind, so a clean run does not prove the logic is correct.
Related AP Computer Science A Guides
Vocabulary
The following words are mentioned explicitly in the College Board Course and Exam Description for this topic.Term | Definition |
|---|---|
ArrayList | A resizable array implementation in Java that can dynamically grow or shrink to store a collection of objects. |
ConcurrentModificationException | An exception that occurs when the size of an ArrayList is changed while traversing it using an enhanced for loop. |
enhanced for loop | A Java loop construct that iterates through all elements of a collection without using an index variable. |
IndexOutOfBoundsException | An exception that occurs when attempting to access an index value outside the valid range of an ArrayList. |
iteration | A form of repetition in which code is executed zero or more times based on a condition. |
recursive statements | Programming statements that call themselves to process elements in a data structure. |
traverse | To visit each element in a data structure (such as a string, array, or ArrayList) in a systematic way, often using recursion. |
Frequently Asked Questions
What does it mean to traverse an ArrayList?
Traversing an ArrayList means using iteration or recursion to access all elements, or an ordered sequence of elements, in the list.
Which loop should I use to traverse an ArrayList?
Use an indexed for loop or while loop when you need the index, need to call set, or need to remove elements. Use an enhanced for loop for clean read-only traversal.
Why can removing elements in a forward loop skip items?
When you remove an element at index i, later elements shift left. If the loop then increments i, it skips the element that shifted into the current position.
How do you safely remove elements while traversing an ArrayList?
Two common AP CSA-safe methods are looping backward from size() - 1 to 0, or using an indexed forward loop and adjusting the index after a removal.
Can you add or remove elements in an enhanced for loop?
No. Changing the size of an ArrayList during an enhanced for loop can cause a ConcurrentModificationException, so use an indexed loop when the size may change.
What causes an IndexOutOfBoundsException with ArrayLists?
An IndexOutOfBoundsException happens when code tries to access an index outside the valid range from 0 to size() - 1.