[英]How to safely remove other elements from a Collection while iterating through the Collection
我正在迭代一個強制執行故障快速迭代器概念的JRE Collection
,因此如果在迭代時修改Collection
則拋出ConcurrentModificationException
,而不是使用Iterator.remove()
方法。 但是,如果對象滿足條件,我需要刪除對象的“邏輯伙伴”。 從而防止合作伙伴被處理。 我怎樣才能做到這一點? 也許為此目的使用更好的收集類型?
例。
myCollection<BusinessObject>
for (BusinessObject anObject : myCollection)
{
if (someConditionIsTrue)
{
myCollection.remove(anObjectsPartner); // throws ConcurrentModificationException
}
}
謝謝。
這不是系列的錯,它是你使用它的方式。 在迭代中途修改集合會導致此錯誤(這是一件好事,因為迭代通常無法明確地繼續)。
編輯 :重新閱讀問題后,這種方法將無效,但我將其留在這里作為一般情況下如何避免此問題的示例。
你想要的是這樣的:
for (Iterator<BusinessObject> iter = myCollection.iterator; iter.hasNext(); )
{
BusinessObject anObject = iter.next();
if (someConditionIsTrue)
{
iter.remove();
}
}
如果你通過迭代器本身刪除對象,它就會知道刪除對象,一切都按照你的預期運行。 請注意,雖然我認為所有標准集合在這方面都能很好地工作,但是迭代器不需要實現remove()方法,所以如果你無法控制myCollection
的類(以及返回的迭代器的實現類),你可能需要在那里進行更多的安全檢查。
另一種方法(例如,如果您不能保證迭代器支持remove()
並且您需要此功能)是創建要迭代的集合的副本 ,然后從原始集合中刪除元素。
編輯 :你可以使用后一種技術來實現你想要的,但是你最終還是會回到迭代器首先拋出異常的原因: 如果你刪除了一個沒有的元素,迭代應該做什么到了嗎? 刪除(或不刪除)當前元素是相對明確定義的,但是你談到刪除當前元素的伙伴 ,我認為它可以在迭代中的隨機點。 由於沒有明確的方法可以處理這個問題,因此您需要自己提供某種形式的邏輯來應對這種情況。 在這種情況下,我傾向於在迭代期間創建和填充新集合,然后在最后將其分配給myCollection
變量。 如果這是不可能的,那么跟蹤要刪除的伙伴元素並調用myCollection.removeAll
就可以了。
您想要從列表中刪除項目並繼續在同一列表上進行迭代。 您是否可以實施兩步解決方案,在步驟1中,您收集要在臨時收集中刪除的項目,並在步驟2中識別它們后將其刪除?
一些想法(這取決於集合中兩個對象之間的關系到底是什么):
您可以先嘗試找到要刪除的所有項目,然后在處理完整個列表后刪除它們。 在找到它們時跳過已刪除的項目。
myCollection<BusinessObject>
List<BusinessObject> deletedObjects = new ArrayList(myCollection.size());
for (BusinessObject anObject : myCollection)
{
if (!deletedObjects.contains(anObject))
{
if (someConditionIsTrue)
{
deletedObjects.add(anObjectsPartner);
}
}
}
myCollection.removeAll(deletedObjects);
CopyOnWriteArrayList將執行您想要的操作。
為什么不使用所有原始BusinessObject的集合,然后使用一個與它們相關聯的單獨類(例如Map)(即創建合作伙伴)? 將它們作為復合元素放在它自己的類中,以便在刪除Business對象時始終可以刪除Partner。 每次需要從Collection中刪除BusinessObject時,不要讓調用者負責。
IE
class BusinessObjectCollection implements Collection<BusinessObject> {
Collection<BusinessObject> objects;
Map<BusinessObject, BusinessObject> associations;
public void remove(BusinessObject o) {
...
// remove from collection and dissasociate...
}
}
最好的答案是第二個,使用迭代器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.