7

我希望迭代一个集合,但集合的内容将在其迭代期间修改。我希望在创建迭代器时迭代原始集合,而不是迭代添加到集合中的任何新元素。这怎么可能?这是 set 的默认行为还是我该如何完成?

我能想到的一种方法是从原始集合中获取一个不会被修改的新集合,但这似乎不优雅,必须有更好的解决方案。

4

6 回答 6

8

如果您想确保没有看到任何新元素,对我来说拍摄场景快照听起来完全是正确的解决方案。有一些集合ConcurrentSkipListSet可以让你继续迭代,但我看不到任何关于迭代器在查看新元素方面的行为的保证。

编辑:CopyOnWriteArraySet有你需要的要求,但写入很昂贵,这听起来不适合你。

这些是我能看到的唯一套装java.util.concurrent,这是此类系列的自然包装。复制仍然可能更简单:)

于 2012-06-19T18:22:08.093 回答
7

编辑:这个答案是为单线程案例设计的,因为我将 OP 的问题解释为避免共修改而不是避免多线程问题。我把这个答案留在这里,以防它对将来使用单线程方法的任何人有用。

没有直接的方法可以做到这一点。然而,一个非常好的选择是有两个集合——你迭代的主集合,以及你插入所有需要添加的新元素的辅助集合。然后,您可以迭代主集,然后在完成后使用addAll将所有新元素添加到主集。

例如:

Set<T> masterSet = /* ... */

Set<T> newElems = /* ... */
for (T obj: masterSet) {
     /* ... do something to each object ... */
}

masterSet.addAll(newElems);

希望这可以帮助!

于 2012-06-19T18:21:56.217 回答
2

制作副本Set 优雅的解决方案。

Set<Obj> copyOfObjs = new HashSet<Obj>(originalSet);
for(Obj original : originalSet) {
    //add some more stuff to copyOfObjs
}
于 2012-06-19T18:22:42.737 回答
0

As others have suggested here, there is no optimal solution to what you search for. It all depends on the use-case of your application, or the usage of the set
Since Set is an interface you might define your own DoubleSet class which will implement Set and let's say will use two HashSet fields.
When you retrieve an iterator, you should mark one of these sets to be in "interation only mode", so the add method will add only to the other set


I am still new to Stackoverlflow, so I need to understand how to embed code in my answers :( but in general you should have a class called MySet (Generic of generic type T) implementing Set of generic type T.
You need to implement all the methods, and have two fields - one is called iterationSet and the other is called insertionSet.
You will also have a boolean field indicating if to insert to the two sets or not. When iterator() method is called, this boolean should be set to false, meaning you should insert only to the insertionSet.
You should have a method that will synchronize the content of the two sets once you're done with the iterator.
I hope I was clear

于 2012-06-19T18:35:39.533 回答
0

您可以将ConcurrentHashMap 与虚拟键一起使用。或ConcurrentSkipListSet

于 2012-06-19T18:22:17.340 回答
0

现在OP已经明确了要求,解决方案是

  1. 在迭代之前复制集合
  2. 使用CopyOnWriteArraySet
  3. 编写您自己的自定义代码并尝试比许多聪明人更聪明。

#1的缺点是即使可能不需要它也总是复制集合(例如,如果在迭代时实际上没有插入)我建议使用选项#2,除非您证明频繁的插入会导致真正的性能问题。

于 2012-06-19T18:25:55.323 回答