12

在 C# 中,IEnumerator接口定义了一种遍历集合并查看元素的方法。我认为这非常有用,因为如果您传递IEnumerable<T>给一个方法,它不会修改原始源代码。

但是,在 Java 中,Iterator删除操作定义为(可选!)允许删除元素。Iterable<T>传递给方法没有任何优势,因为该方法仍然可以修改原始集合。

remove可选性是拒绝遗赠气味的一个例子,但忽略这一点(已经在这里讨论过)我会对促使remove事件在接口上实现的设计决策感兴趣。

导致remove被添加到的设计决策是Iterator什么?

换句话说,明确没有remove定义的 C# 设计决策是IEnumerator什么?

4

4 回答 4

8

Iterator能够在迭代期间删除元素。您不能使用迭代器迭代集合并使用remove()该集合的方法从目标集合中删除元素。您将获得ConcurrentModificationException下一次调用,Iterator.next()因为迭代器无法知道集合究竟是如何更改的,也无法知道如何继续迭代。

当您使用remove()迭代器时,它知道集合是如何更改的。此外,实际上您不能删除集合的任何元素,只能删除当前元素。这简化了迭代的继续。

关于传递迭代器或迭代器的优点:您始终可以使用Collection.unmodifireableSet()Collection.unmodifireableList()防止修改您的集合。

于 2012-07-25T11:18:58.457 回答
2

这可能是由于在迭代集合时从集合中删除项目一直是导致错误和奇怪行为的原因。从阅读文档中可以看出,Java 在运行时强制 remove() 每次调用 next() 时只调用一次,这让我认为它刚刚被添加以防止人们在迭代列表时弄乱从列表中删除数据。

于 2012-07-25T11:21:17.193 回答
1

在某些情况下,您希望能够使用迭代器删除元素,因为这是最有效的方法。例如,当遍历链接数据结构(例如链接列表)时,使用迭代器删除是一个O(1)操作......与O(N)通过List.remove()操作相比。

当然,许多集合的设计是为了在集合期间通过任何其他方式修改集合,而不是Iterator.remove()导致ConcurrentModificationException.


如果您不想允许通过集合迭代器进行修改,则使用它的迭代器包装它Collection.unmodifiableXxxx并使用它的迭代器将产生预期的效果。或者,我认为 Apache Commons 提供了一个简单的不可修改的迭代器包装器。


顺便说一句IEnumerable,与Iterator. 看看reset()方法。我也很好奇 C#LinkedList类如何处理O(N)删除问题。似乎它是通过以值是引用的and属性的形式公开列表的内部结构来做到这一点的。这违反了另一个设计原则......并且(IMO)比.FirstLastLinkedListNodeIterator.remove()

于 2012-07-25T11:19:36.757 回答
-1

这实际上是 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,我不需要所有这些,因为当我在一个项目上时,我可以删除它,但迭代将继续!老实说,虽然它可能看起来不合适,但它在很多方面确实是一种优化。

于 2012-07-25T11:27:49.450 回答