使用带有Maps键集的流时出现ConcurrentModificationException [英] ConcurrentModificationException when using stream with Maps key set

查看:100
本文介绍了使用带有Maps键集的流时出现ConcurrentModificationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想删除 someMap 中的所有项目 someList 中不存在哪些键。看看我的代码:

I want to remove all items from someMap which keys are not present in someList. Take a look into my code:

someMap.keySet().stream().filter(v -> !someList.contains(v)).forEach(someMap::remove);

我收到 java.util.ConcurrentModificationException 。为什么?流不是平行的。最优雅的方法是什么?

I receive java.util.ConcurrentModificationException. Why? Stream is not parallel. What is the most elegant way to do this?

推荐答案

@Eran已经解释了如何更好地解决这个问题。我将解释为什么发生 ConcurrentModificationException

@Eran already explained how to solve this problem better. I will explain why ConcurrentModificationException occurs.

ConcurrentModificationException 因为您正在修改流源而发生。您的地图可能是 HashMap TreeMap 或其他非并发地图。我们假设它是 HashMap 。每个流都由 Spliterator <支持/ code> 。如果spliterator没有 IMMUTABLE CONCURRENT 特征,那么,正如文档所说:

The ConcurrentModificationException occurs because you are modifying the stream source. Your Map is likely to be HashMap or TreeMap or other non-concurrent map. Let's assume it's a HashMap. Every stream is backed by Spliterator. If spliterator has no IMMUTABLE and CONCURRENT characteristics, then, as documentation says:


绑定Spliterator后,如果检测到结构性干扰,应尽力抛出 ConcurrentModificationException 。执行此操作的Spliterators称为 fail-fast

After binding a Spliterator should, on a best-effort basis, throw ConcurrentModificationException if structural interference is detected. Spliterators that do this are called fail-fast.

所以 HashMap。 keySet()。spliterator()不是 IMMUTABLE (因为这个 Set 可以修改)而不是 CONCURRENT (并发更新对 HashMap 不安全)。所以它只检测并发更改并抛出 ConcurrentModificationException 作为spliterator文档规定。

So the HashMap.keySet().spliterator() is not IMMUTABLE (because this Set can be modified) and not CONCURRENT (concurrent updates are unsafe for HashMap). So it just detects the concurrent changes and throws a ConcurrentModificationException as spliterator documentation prescribes.

还值得引用< a href =https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html =noreferrer> HashMap 文档:

Also it worth citing the HashMap documentation:


所有类的集合视图方法返回的迭代器都是 fail-fast :如果在创建迭代器之后的任何时候对映射进行结构修改,除了通过迭代器自己的remove方法之外,迭代器将抛出 ConcurrentModificationException 。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险。

The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

注意迭代器的快速失败行为无法得到保证,因为一般来说,在存在非同步并发修改的情况下,不可能做出任何硬性保证。失败快速迭代器尽力抛出 ConcurrentModificationException 。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的故障快速行为应仅用于检测错误

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

虽然它只是关于迭代器,但我相信对于分裂者来说也是如此。

While it says about iterators only, I believe it's the same for spliterators.

这篇关于使用带有Maps键集的流时出现ConcurrentModificationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆