并发模式使用具有地图键集的流时的异常
我想删除 所有键不存在的项目。看看我的代码:someMap
someList
someMap.keySet().stream().filter(v -> !someList.contains(v)).forEach(someMap::remove);
我收到.为什么?流不是并行的。最优雅的方法是什么?java.util.ConcurrentModificationException
我想删除 所有键不存在的项目。看看我的代码:someMap
someList
someMap.keySet().stream().filter(v -> !someList.contains(v)).forEach(someMap::remove);
我收到.为什么?流不是并行的。最优雅的方法是什么?java.util.ConcurrentModificationException
@Eran已经解释了如何更好地解决这个问题。我将解释为什么会发生。ConcurrentModificationException
发生这种情况是因为您正在修改流源。您的可能是 或 或其他非并发映射。让我们假设它是一个.每个流都由Spliterator
支持。如果分路器没有和特性,那么,正如文档所说:ConcurrentModificationException
Map
HashMap
TreeMap
HashMap
IMMUTABLE
CONCURRENT
绑定后,如果检测到结构干涉,则应尽最大努力投掷分路器。执行此操作的拆分器称为快速故障。
ConcurrentModificationException
因此,不是(因为这可以修改)也不是(并发更新对于 )因此,它只是检测并发更改并抛出一个 as spliterator 文档规定。HashMap.keySet().spliterator()
IMMUTABLE
Set
CONCURRENT
HashMap
ConcurrentModificationException
同样值得引用HashMap
文档:
所有此类的“集合视图方法”返回的迭代器都是失败快速的:如果在创建迭代器后的任何时候对映射进行了结构修改,则除了通过迭代器自己的 remove 方法之外,迭代器将抛出一个 .因此,面对并发修改,迭代器会快速干净地失败,而不是在未来不确定的时间冒着任意的非确定性行为的风险。
ConcurrentModificationException
请注意,迭代器的故障快速行为无法得到保证,因为一般来说,在存在不同步并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器以尽力而为。因此,编写一个依赖于此异常的正确性的程序是错误的:迭代器的故障快速行为应该仅用于检测错误。
ConcurrentModificationException
虽然它只说迭代器,但我相信对于拆分器也是如此。
您不需要API。在 上使用。返回的任何更改都将反映在原始 .Stream
retainAll
keySet
Set
keySet()
Map
someMap.keySet().retainAll(someList);