Iterator使用需遵守契约:必须先hasNext()再next(),remove()仅限next()后立即调用;foreach本质是Iterator,禁止直接修改集合;ListIterator支持双向遍历但仅适用于List。
直接调用 next() 而不检查 hasNext(),几乎必然抛出 NoSuchElementException。这不是设计缺陷,而是 Iterator 的契约:它不负责“预判”是否还有元素,只负责“取下一个”。
while (iterator.hasNext()) { Object o = iterator.next(); ... }
next()(比如想跳过一个元素)会导致漏读——每次 next() 都推进内部指针iterator() 返回有效对象,但首次 hasNext() 就返回 false,不会报错Iterator.remove() 是唯一安全的集合遍历中删除元素的方式,但它有严格时序约束:必须在调用 next() 之后、且在下一次 next() 之前调用;重复调用或在 hasNext() 后直接调用会触发 IllegalStateException。
iterator.remove(); // IllegalStateException:还没 next()
iterator.next(); iterator.next(); iterator.remove(); // IllegalStateException:上个 next 已被覆盖
Java 的 for (String s : list) 本质是语法糖,编译后等价于显式使用 Iterator。这意味着:在 foreach 中调用 list.remove() 或 list.add() 会立刻触发 ConcurrentModificationException——即使单线程也如此。
modCount 与迭代器持有的 expectedModCount 不匹配iterator.remove()(安全删除),或收集待删元素再批量操作(如 removeAll(toRemove))CopyOnWriteArrayList 是例外,它的迭代器不检查并发修改,但代价是每次写都复制数组,不适合高频写场景ListIterator 是 Iterator 的子接口,只由 ArrayList、LinkedList 等 List 实现提供。它能向前/向后移动、获取当前位置索引、甚至设置当前元素值。
listIterator() 从头开始;listIterator(int index) 从指定索引开始(索引可等于 list.size(),此时 hasPrevious() 为 true,hasNext() 为 false)nextIndex() 和 previousIndex() 返回的是“下一次 next() 或 previous() 将访问的索引
”,不是当前元素索引Set 或 Map —— 它们没有定义顺序索引的概念ConcurrentModificationException 上,其实问题不在“并发”,而在于没意识到 foreach 和显式 Iterator 共享同一套检测机制。