[英]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提供了一個簡單的不可修改的迭代器包裝器。
順便說一下IEnumerable
與Iterator
一樣有“氣味”。 看一下reset()
方法。 我也很好奇C# LinkedList
類如何處理O(N)
刪除問題。 它似乎是通過公開列表的內部 ......以First
和Last
屬性的形式來實現這一點,它們的值是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.