我希望遍歷集合,但集合的內容將在其迭代過程中修改。我希望在迭代器創建時迭代原始集合,而不是迭代添加到集合中的任何新元素。這怎麼可能?這是設置的默認行爲還是我該如何實現?Java:在修改集合的內容的同時迭代集合
我可以想到的一種方法是從原始集合中得到一個不會被修改的新集合,但這看起來不夠優雅,必須有更好的解決方案。
我希望遍歷集合,但集合的內容將在其迭代過程中修改。我希望在迭代器創建時迭代原始集合,而不是迭代添加到集合中的任何新元素。這怎麼可能?這是設置的默認行爲還是我該如何實現?Java:在修改集合的內容的同時迭代集合
我可以想到的一種方法是從原始集合中得到一個不會被修改的新集合,但這看起來不夠優雅,必須有更好的解決方案。
如果你想確保你沒有看到任何新的元素,那麼拍攝這個設置的快照聽起來像是對我來說正確的解決方案。有一些例如ConcurrentSkipListSet
這將允許你保持迭代,但我不能看到圍繞看到新元素方面的迭代器行爲的任何保證。
編輯:CopyOnWriteArraySet
有你需要的要求,但寫入很貴,這聽起來不適合你。
這些是我可以在java.util.concurrent
中看到的唯一設置,這是這類收藏的自然包裝。拍攝副本仍然可能更簡單:)
這取決於。如果快照_isn't_不需要(在迭代時沒有人碰巧插入)CopyOnWriteArraySet會更快。所以這取決於實際發生碰撞的頻率。 – user949300
@ user949300:我不知道CopyOnWriteArraySet真正需要複製的細節,但文檔聲稱它是「通常」(無論如何)。如果只在真正需要的時候複製,它肯定會很好。 –
編輯:這個答案是爲單線程案件設計的,因爲我已經將OP的問題解釋爲避免通用化,而不是避免多線程問題。我在這裏留下了這個答案,以防將來對任何使用單線程方法的人有用。
有沒有直接的方法來實現這一點。但是,一個非常好的選擇是有兩套 - 主迭代,您要迭代的主集和輔助集,其中插入所有需要添加的新元素。然後,您可以遍歷主集,然後完成並使用addAll
將所有新元素添加到主集。
例如:
Set<T> masterSet = /* ... */
Set<T> newElems = /* ... */
for (T obj: masterSet) {
/* ... do something to each object ... */
}
masterSet.addAll(newElems);
希望這有助於!
我喜歡這種方法,因爲(a)與複製整個原始集合相比,它產生的臨時對象更少,(b)避免了可能不需要的大量併發開銷。 ''我看不到任何關於迭代器行爲的看法,因爲看到新元素'可能是'ConcurrentSkipListSet'的一個問題。 –
我不確定這是如何工作的。第二個線程如何知道它必須添加到newElems中,而不是masterSet?而且,如果你不迭代,誰知道然後將newElems合併到masterSet中? – user949300
@ user949300-我會假設任何代碼都是添加元素到設置可能知道什麼是新的元素設置。另外請注意OP的問題沒有提到多線程的問題;我認爲這個問題是協調而不是併發。如果這些新信息存在,那麼將這些新信息傳達給其他線程將非常容易。 – templatetypedef
您可以使用帶虛擬鍵的ConcurrentHashMap。 還是一個ConcurrentSkipListSet
製作的Set
副本優雅的解決方案。
Set<Obj> copyOfObjs = new HashSet<Obj>(originalSet);
for(Obj original : originalSet) {
//add some more stuff to copyOfObjs
}
現在OP澄清的要求,解決方案是
#1的缺點是你總是複製集合,即使它可能不需要(例如,如果迭代時沒有實際發生插入)我會建議選項#2,除非你證明頻繁插入是造成真正的性能問題。
正如其他人在這裏所建議的那樣,對於您搜索的內容沒有最佳解決方案。這一切都取決於您的應用程序的用例或集合的用法
由於Set是一個接口,您可以定義您自己的DoubleSet類,它將實現Set,讓我們假設將使用兩個HashSet字段。
當你檢索一個迭代器時,你應該將其中一個集合標記爲「interation only mode」,所以add方法將只添加到另一個集合
我還是Stackoverlflow的新手,所以我需要了解如何在我的答案中嵌入代碼:(但一般來說,您應該有一個名爲MySet(通用類型T的通用類)的類實現通用類型T. Set
您需要實現所有方法,並且有兩個字段 - 一個被稱爲iterationSet,另一個被稱爲插入集
你也將有一個boolean字段指示是否插入到兩個集合當調用iterator()方法時,這個布爾值應該設置爲false,這意味着你應該插入僅限於插入集。
您應該有一種方法,可以在完成迭代器後同步兩組內容。
我希望我很清楚
你提出的方式似乎很好。 – assylias
澄清 - 這是單線程還是多線程? – templatetypedef
多線程。一個線程正在迭代,另一個線程正在改變集合。我不希望暫停任何性能問題的線程。 – nomel7