簡體   English   中英

如何在迭代Collection時安全地從Collection中刪除其他元素

[英]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中識別它們后將其刪除?

一些想法(這取決於集合中兩個對象之間的關系到底是什么):

  1. 以對象為鍵,伙伴為值的Map。
  2. 一個CopyOnWriteArrayList,但是當你擊中伙伴時你必須注意
  3. 將副本復制到另一個Collection對象中,並迭代一個,刪除另一個。 如果這個原始集合可以是一個集合,那么這將有助於刪除。

您可以先嘗試找到要刪除的所有項目,然后在處理完整個列表后刪除它們。 在找到它們時跳過已刪除的項目。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM