4.9 - ArrayList Traversals
You can traverse an
ArrayList the same general way you traverse an array, with a loop.With an indexed loop, use
size() for the bound and get(i) to access each element. An enhanced for loop works too. (Recursion can also traverse an ArrayList, see 4.17.)ArrayList<String> names = new ArrayList<String>(); names.add("Alex"); names.add("Sam"); names.add("Jordan"); // indexed for loop for (int i = 0; i < names.size(); i++) { System.out.println(names.get(i)); } // enhanced for loop for (String name : names) { System.out.println(name); }
Trying to access an index out of range throws an
IndexOutOfBoundsException.ArrayList<String> names = new ArrayList<String>(); names.add("Alex"); String bad = names.get(5); // IndexOutOfBoundsException
Notice the name: an array throws an
ArrayIndexOutOfBoundsException, but an ArrayList throws an IndexOutOfBoundsException. Valid indices are 0 through size() - 1.One big gotcha: if you’re deleting elements while traversing the list, you can accidentally skip elements, since everything shifts left after a removal. You need to be careful with your index bookkeeping.
// Careful traversal-with-removal pattern (using an indexed loop and decrementing i) for (int i = 0; i < names.size(); i++) { if (names.get(i).equals("Sam")) { names.remove(i); i--; // step back so we don't skip the next element } }
Here’s why that
i-- matters. Without it, two matches in a row means one gets skipped:// names is [Sam, Sam, Alex] for (int i = 0; i < names.size(); i++) { if (names.get(i).equals("Sam")) { names.remove(i); // no i-- } } // names is [Sam, Alex], the second Sam was skipped
When
i is 0, the first Sam is removed and the second Sam slides into index 0. Then i goes up to 1, so index 0 never gets checked again.Another safe way is to traverse backward. Removing an element only shifts the elements after it, and you’ve already checked those:
// names is [Sam, Sam, Alex] for (int i = names.size() - 1; i >= 0; i--) { if (names.get(i).equals("Sam")) { names.remove(i); } } // names is [Alex]
Another important rule: don’t add or remove elements while using an enhanced for loop to traverse an
ArrayList, this throws a ConcurrentModificationException.// names is [Alex, Sam, Jordan] for (String name : names) { if (name.equals("Sam")) { names.add("Max"); // ConcurrentModificationException } }
Removing inside an enhanced for loop is just as bad: depending on where the removed element was, you either get the exception or the loop quietly ends early and skips elements. Whenever you need to add or remove, use an indexed loop.