簡體   English   中英

為什么迭代器定義了remove()操作?

[英]Why does Iterator define the remove() operation?

在C#中, IEnumerator接口定義了一種遍歷集合並查看元素的方法。 我認為這非常有用,因為如果將IEnumerable<T>傳遞給方法,它不會修改原始源。

但是,在Java中, Iterator刪除操作定義為(可選!)允許刪除元素。 Iterable<T>傳遞給方法沒有任何優勢,因為該方法仍然可以修改原始集合。

remove可選性拒絕遺贈氣味的一個例子,但忽略了(已經在這里討論 ),我會對促使在界面上實現remove事件的設計決策感興趣。

什么是導致remove被添加到Iterator的設計決策?

換句話說,在IEnumerator上明確沒有remove的C#設計決策是什么?

Iterator可以在迭代期間刪除元素。 您不能使用迭代器迭代集合,並使用該集合的remove()方法從目標集合中刪除元素。 您將在下次調用Iterator.next()時收到ConcurrentModificationException ,因為迭代器無法知道集合的確切更改方式,也無法知道如何繼續迭代。

當您使用迭代器的remove() ,它知道如何更改集合。 而且實際上你不能刪除任何集合元素但只刪除當前元素。 這簡化了迭代的繼續。

關於傳遞迭代器或Iterable的優點:您始終可以使用Collection.unmodifireableSet()Collection.unmodifireableList()來防止修改集合。

這可能是因為從迭代中刪除集合中的項目一直是導致錯誤和奇怪行為的原因。 通過閱讀文檔,它會建議Java在運行時強制執行remove()僅在每次調用next()時調用一次,這使我認為它剛剛被添加以防止人們在迭代時從列表中刪除數據。

在某些情況下,您希望能夠使用迭代器刪除元素,因為這是最有效的方法。 例如,當遍歷鏈接數據結構(例如鏈表)時,使用迭代器刪除是O(1)操作...通過List.remove()操作與O(N)進行比較。

當然, 許多集合的設計使得在集合期間通過Iterator.remove()之外的任何其他方式修改集合將導致ConcurrentModificationException


如果您不希望允許通過集合迭代器進行修改,則使用Collection.unmodifiableXxxx將其包裝並使用它的迭代器將具有所需的效果。 或者,我認為Apache Commons提供了一個簡單的不可修改的迭代器包裝器。


順便說一下IEnumerableIterator一樣有“氣味”。 看一下reset()方法。 我也很好奇C# LinkedList類如何處理O(N)刪除問題。 它似乎是通過公開列表的內部 ......以FirstLast屬性的形式來實現這一點,它們的值是LinkedListNode引用。 這違反了另一個設計原則......並且(IMO)比Iterator.remove()危險得多。

這實際上是Java的一個很棒的功能。 您可能知道,在迭代.NET中的列表以刪除元素(其中有許多用例)時,您只有兩個選項。

var listToRemove = new List<T>(originalList);
foreach (var item in originalList)
{
    ...
    if (...)
    {
        listToRemove.Add(item)
    }
    ...
}

foreach (var item in listToRemove)
{
    originalList.Remove(item);
}

要么

var iterationList = new List<T>(originalList);
for (int i = 0; i < iterationList.Count; i++)
{
    ...
    if (...)
    {
        originalList.RemoveAt(i);
    }
    ...
}

現在,我更喜歡第二種,但是使用Java我並不需要所有這些,因為當我在一個項目上時我可以刪除它,但迭代將繼續! 老實說,盡管看起來不合適,但它在很多方面都是一種優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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