You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala可变HashSet迭代删元素是否安全?自定义dumbRetain能否免并发异常?

关于Scala可变HashSet迭代与自定义retain方法的问题解答

问题1:迭代collection.mutable.HashSet时移除元素是否安全?

答案是不安全。Scala的collection.mutable.HashSet底层依赖Java的哈希表实现,它的迭代器采用fail-fast设计:迭代器初始化时会记录集合的修改计数器,每次调用next()都会检查当前集合的修改计数是否和迭代器保存的一致。如果在迭代过程中直接调用集合的remove()方法(而非迭代器自身的remove()),就会触发计数器不匹配,抛出ConcurrentModificationException。

举个典型的反例:

import scala.collection.mutable.HashSet

val set = HashSet(1,2,3,4)
for (elem <- set) {
  if (elem % 2 == 0) set.remove(elem) // 大概率会抛出ConcurrentModificationException
}

只有使用迭代器自身的remove()方法才是安全的:

val iter = set.iterator
while (iter.hasNext) {
  val elem = iter.next()
  if (elem % 2 == 0) iter.remove() // 符合迭代器安全操作规范
}

问题2:自定义dumbRetain方法未触发异常,是否可以放心使用?

你当前没碰到异常只是偶然行为,绝对不能依赖这种“无异常”的情况。

虽然你提到SI-7269的问题源于JavaConversions包装的Java集合,但Scala原生的mutable.HashSet本身就带有fail-fast的检查机制。你没触发异常可能是这些场景:

  • 你移除的元素是迭代器已经遍历过的,此时迭代器后续的next()不会检测到这个修改;
  • 集合规模很小,修改操作的时机刚好避开了迭代器的检查逻辑;
  • 测试用例覆盖不全,没有触发计数器不匹配的场景。

一旦场景变化(比如集合增大、移除的是未遍历的元素),ConcurrentModificationException一定会找上门。

安全实现retain逻辑的建议

  • 优先使用Scala内置的retain方法,它是官方实现,已经处理了所有安全迭代的细节;
  • 如果要自己实现,要么用迭代器的remove()方法过滤元素,要么先收集所有需要保留的元素,再重建集合:
def safeRetain(set: mutable.HashSet[Int], predicate: Int => Boolean): Unit = {
  val toKeep = set.filter(predicate).toSet
  set.clear()
  set ++= toKeep
}

内容的提问来源于stack exchange,提问作者Dylan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:06:35