Enumeration 不抛 ConcurrentModificationException,因其不维护 modCount、无 expectedModCount 校验,仅提供只读遍历,无法删除或修改集合,故不触发快速失败机制。

Enumeration 不检查 modCount,所以不会抛 ConcurrentModificationException
Enumeration 是 Java 早期集合遍历接口(比如 Vector.elements()、Hashtable.keys() 返回的类型),它压根不维护或比对 modCount 字段。遍历时哪怕底层集合被其他线程或代码修改了,它既不记录初始状态,也不在每次 nextElement() 前校验一致性,因此永远不会触发快速失败逻辑。
Enumeration 只读 + 无删除能力,天然规避了结构变更风险
它只提供 hasMoreElements() 和 nextElement() 两个方法,不能增删改集合内容,也不暴露迭代位置。这意味着:
- 调用方无法在遍历中调用
remove()或add()—— 这些操作根本不在接口里 - 没有
expectedModCount缓存值,也就没有“预期 vs 实际”校验环节 - 即使集合内部发生了并发修改,Enumeration 仍会继续返回元素(可能看到脏数据或漏掉新元素,但不会崩溃)
对比 Iterator 就能看清设计差异
Iterator 的 next() 方法开头必有类似这样的校验:
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
而 Enumeration 的 nextElement() 实现(如 Vector$1 匿名类)里完全没这行逻辑。它只是按当前数组/链表状态顺序取值,连“当前是否过期”都不关心。
这也解释了为什么 Enumeration 被 Iterator 取代:不是它更安全,而是它太简单、太被动——不报错不等于正确,只是把问题留给调用者自己兜底。
别误以为 Enumeration “线程安全”
它不抛 ConcurrentModificationException,不代表多线程下行为可预测:
- 多个线程同时用同一个
Enumeration遍历,可能互相干扰游标(取决于具体实现,比如Vector的枚举器是同步的,但Hashtable的不是) - 遍历中途集合被修改,结果可能是部分旧值 + 部分新值,甚至数组越界(
ArrayIndexOutOfBoundsException),但它不会主动拦截 - 现代代码应避免直接使用
Enumeration,除非对接遗留 API(如 JNDI、ServletContext.getAttributeNames())
真正需要并发安全的遍历,请用 java.util.concurrent 包下的容器(如 ConcurrentHashMap)及其迭代器,它们走的是 fail-safe 路线,而非靠沉默回避问题。










