CopyOnWriteArrayList迭代器基于不可变快照设计,不支持任何写操作。它在创建时保存数组引用,后续遍历始终基于该固定副本,与list写操作完全隔离;所有add/set/remove均需复制整个数组,迭代器无同步机制且主动抛出UnsupportedOperationException。

因为它的迭代器底层保存的是创建时刻的数组快照,所有写操作(包括 add、set、remove)都会触发全新数组复制,而迭代器本身不持有对底层数组的修改权限,也不维护与当前 list 的同步状态。
迭代器基于“不可变快照”设计
调用 iterator() 时,CopyOnWriteArrayList 会把当前数组引用直接封装进迭代器——这个引用指向的是一个固定版本的数组副本。后续无论 list 如何通过 add/set/remove 生成新数组,该迭代器始终遍历原始快照,不会感知变化,也不会尝试更新它。
- 快照一旦生成,就与 list 后续的写操作完全隔离
- 迭代器没有字段记录 list 当前数组地址,也没有锁或回调机制去同步更新
- 因此它天然不具备修改能力,不是“暂时禁用”,而是架构上就不支持
写操作必须重建整个数组
CopyOnWriteArrayList 的所有可变操作(add/set/remove)都走同一套流程:加锁 → 获取当前数组 → Arrays.copyOf 创建新数组 → 修改新数组 → 替换底层数组引用。这个过程开销大,且与迭代器无关。
-
set(int index, E element)看似只改一个位置,但实际仍要复制全部元素 - 如果允许迭代器调用 set,就得让它也触发数组复制,这会破坏快照语义——它本应只读
- 更关键的是,多个迭代器可能同时存在,谁负责触发复制?复制后该通知哪些迭代器失效?没有统一协调机制
API 层面明确拒绝写操作
它的迭代器实现类(如 COWIterator)直接抛出 UnsupportedOperationException,这是设计上的主动约束,而非能力缺失。
立即学习“Java免费学习笔记(深入)”;
- 调用
iterator.remove()、iterator.set(...)或iterator.add(...)都会立即失败 - 这种“硬拦截”避免了语义混淆:比如用户误以为 iterator.remove() 是删除当前元素,实际上它既不删 list 也不删快照,逻辑无意义
- 强制开发者区分“遍历”和“修改”两个独立动作,符合读写分离初衷
替代方案清晰且必要
真有修改需求,必须绕过迭代器,直接调用 list 本身的写方法——这反而更安全、语义更明确。
- 要删元素,用
list.removeIf(predicate)或先收集索引再批量 remove - 要改元素,用
list.set(index, newValue),注意这会生成新数组,不影响已有迭代器 - 若需边遍历边筛选,建议用 stream + collect 或构造新 list,避免在迭代中隐式修改


















