2012-06-19 143 views
7

我希望遍历集合,但集合的内容将在其迭代过程中修改。我希望在迭代器创建时迭代原始集合,而不是迭代添加到集合中的任何新元素。这怎么可能?这是设置的默认行为还是我该如何实现?Java:在修改集合的内容的同时迭代集合

我可以想到的一种方法是从原始集合中得到一个不会被修改的新集合,但这看起来不够优雅,必须有更好的解决方案。

+2

你提出的方式似乎很好。 – assylias

+1

澄清 - 这是单线程还是多线程? – templatetypedef

+0

多线程。一个线程正在迭代,另一个线程正在改变集合。我不希望暂停任何性能问题的线程。 – nomel7

回答

8

如果你想确保你没有看到任何新的元素,那么拍摄这个设置的快照听起来像是对我来说正确的解决方案。有一些例如ConcurrentSkipListSet这将允许你保持迭代,但我不能看到围绕看到新元素方面的迭代器行为的任何保证。

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

这些是我可以在java.util.concurrent中看到的唯一设置,这是这类收藏的自然包装。拍摄副本仍然可能更简单:)

+0

这取决于。如果快照_isn't_不需要(在迭代时没有人碰巧插入)CopyOnWriteArraySet会更快。所以这取决于实际发生碰撞的频率。 – user949300

+0

@ user949300:我不知道CopyOnWriteArraySet真正需要复制的细节,但文档声称它是“通常”(无论如何)。如果只在真正需要的时候复制,它肯定会很好。 –

7

编辑:这个答案是为单线程案件设计的,因为我已经将OP的问题解释为避免通用化,而不是避免多线程问题。我在这里留下了这个答案,以防将来对任何使用单线程方法的人有用。

有没有直接的方法来实现这一点。但是,一个非常好的选择是有两套 - 主迭代,您要迭代的主集和辅助集,其中插入所有需要添加的新元素。然后,您可以遍历主集,然后完成并使用addAll将所有新元素添加到主集。

例如:

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

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

masterSet.addAll(newElems); 

希望这有助于!

+1

我喜欢这种方法,因为(a)与复制整个原始集合相比,它产生的临时对象更少,(b)避免了可能不需要的大量并发开销。 ''我看不到任何关于迭代器行为的看法,因为看到新元素'可能是'ConcurrentSkipListSet'的一个问题。 –

+0

我不确定这是如何工作的。第二个线程如何知道它必须添加到newElems中,而不是masterSet?而且,如果你不迭代,谁知道然后将newElems合并到masterSet中? – user949300

+0

@ user949300-我会假设任何代码都是添加元素到设置可能知道什么是新的元素设置。另外请注意OP的问题没有提到多线程的问题;我认为这个问题是协调而不是并发。如果这些新信息存在,那么将这些新信息传达给其他线程将非常容易。 – templatetypedef

2

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

Set<Obj> copyOfObjs = new HashSet<Obj>(originalSet); 
for(Obj original : originalSet) { 
    //add some more stuff to copyOfObjs 
} 
0

现在OP澄清的要求,解决方案是

  1. 复制迭代
  2. 使用CopyOnWriteArraySet
  3. 编写自己的自定义代码,并尝试比聪明很多之前设定聪明的人。

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

0

正如其他人在这里所建议的那样,对于您搜索的内容没有最佳解决方案。这一切都取决于您的应用程序的用例或集合的用法
由于Set是一个接口,您可以定义您自己的DoubleSet类,它将实现Set,让我们假设将使用两个HashSet字段。
当你检索一个迭代器时,你应该将其中一个集合标记为“interation only mode”,所以add方法将只添加到另一个集合


我还是Stackoverlflow的新手,所以我需要了解如何在我的答案中嵌入代码:(但一般来说,您应该有一个名为MySet(通用类型T的通用类)的类实现通用类型T. Set
您需要实现所有方法,并且有两个字段 - 一个被称为iterationSet,另一个被称为插入集
你也将有一个boolean字段指示是否插入到两个集合当调用iterator()方法时,这个布尔值应该设置为false,这意味着你应该插入仅限于插入集。
您应该有一种方法,可以在完成迭代器后同步两组内容。
我希望我很清楚