ArrayList Traversals · ArrayList 遍历
| English | 中文 | Pinyin · 拼音 |
|---|---|---|
| ConcurrentModificationException/kənˈkʌrənt ˌmɒdɪfɪˈkeɪʃn ekˈsepʃn/ | 并发修改异常 | bìng fā xiū gǎi yì cháng |
Choose a traversal that matches the intended change
- An ArrayList contains [2, 3, 4]. You want to double every stored value, while keeping the number of elements unchanged.
- An indexed loop can use list.set(i, 2 * list.get(i)). Assigning x = 2*x in for (int x : list) changes only the local loop variable.
Starting from list [2, 3, 4], run for (int x : list) { x = 2 * x; }. What is list.get(1)?
Assigning the local primitive x does not replace the stored Integer. The middle list element remains 3.
Looping over a list
- Traverse an ArrayList just like an array, but with its methods. Indexed:
for (int i = 0; i < list.size(); i++) { ... list.get(i) ... } - For-each:
for (String s : list) { ... s ... }— clean for reading values.size()(notlength) bounds the indexed loop.
The same patterns
- Sum, count, min/max, and search all work the same as with arrays. Just swap
a[i]forlist.get(i)anda.lengthforlist.size(). - The accumulator and max/count logic is identical. Everything you learned for array traversal carries over.
Reading vs. modifying
- An enhanced loop copies each element value into its loop variable. For
Integerelements read asint x, assigning toxdoes not replace a list element; an indexed loop can replace it withset(i, x). - For structural changes (adding/removing), use the indexed loop carefully. Reading is simple; removing while looping needs extra care (next lesson).
Summing an ArrayList by index · 按下标对 ArrayList 求和
Bound with size(), read with get(i) (list = [10,20,30]).
The correct condition for an indexed ArrayList loop is...
ArrayList uses size(); arrays use length.
Why should a program avoid direct structural changes during an ArrayList enhanced-for traversal?
ArrayList fail-fast behaviour is best-effort. Avoid unsafe traversal rather than relying on a guaranteed exception.
The array traversal patterns (sum, count, max) work the same for an ArrayList.
Just swap a[i]/a.length for list.get(i)/list.size().
To safely remove elements while traversing a list, you should use...
for-each can't structurally modify; the indexed loop can (carefully).
Without structural modification during traversal, an enhanced loop can read all entries of an ArrayList
The loop reads each stored reference. Structural changes during traversal are a separate concern; this claim does not guarantee all operations on every possible element are safe.
Don't modify during for-each
- Adding or removing during a for-each loop may trigger a ConcurrentModificationException 并发修改异常; fail-fast detection is best-effort. The for-each loop assumes the list doesn't change structure underneath it.
- To remove while traversing, use an indexed loop (and manage the index). Reading with for-each is suitable when the list is not structurally changed during traversal. Also check element requirements: unboxing a null Integer still throws an exception.
Bound an indexed ArrayList loop with list.size(), not .length, and never structurally modify during a for-each. Calling add/remove inside a for (x : list) may trigger a ConcurrentModificationException, but detection is not guaranteed. To delete while traversing, use an indexed loop — and remember remove(i) shifts later elements, so don't blindly i++ past the shifted element.
After the indexed doubling update, what is list.get(1)?
The middle stored value 3 is replaced by 6. Reassigning a primitive loop variable would leave it at 3.
For non-null Student entries, s.addScore(5) inside for (Student s : students) can change stored students without adding or removing list elements.
The copied references reach mutable Student objects. Their fields can change without changing list structure.
Summing an ArrayList
- Indexed:
for (int i = 0; i < list.size(); i++) { sum += list.get(i); } - For-each:
for (int x : list) { sum += x; }(autoboxing/unboxing handles Integer↔int). - Both total the list; for-each is cleaner for read-only.
Carry the reasoning to a new case
- Adding or removing directly during enhanced traversal is unsafe; fail-fast exceptions are best-effort, not a guaranteed correctness check.
- A list of mutable Student objects can be traversed with
for (Student s : students) { s.addScore(5); }, assuming non-null entries. This changes each object's state without changing list structure; assigning a different reference toswould not replace the stored element.
Traverse an ArrayList with an indexed loop (i < list.size(), list.get(i)) or an enhanced loop that receives each element value. The array patterns (sum, count, min/max, search) all carry over. Avoid direct structural changes during an enhanced traversal: a ConcurrentModificationException may detect the bug, but is not guaranteed. Use a carefully managed indexed loop for the removal pattern taught next; changing a referenced object's fields is different from changing list structure.