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()、コレクションがどのように変更されたかがわかります。さらに、実際にはコレクションの要素を削除することはできませんが、現在の要素のみを削除できます。これにより、反復の継続が単純化されます。

iterator または Iterable を渡す利点について: コレクションの変更をいつでも使用Collection.unmodifireableSet()またはCollection.unmodifireableList()防止できます。

于 2012-07-25T11:18:58.457 に答える
2

コレクションを繰り返しながらコレクションからアイテムを削除することが、常にバグや奇妙な動作の原因であったことが原因である可能性があります。ドキュメントを読むと、Javaが実行時にremove()を強制するのはnext()の呼び出しごとに1回だけであることがわかります。これは、リストを反復処理するときにリストからデータを削除することをめちゃくちゃにするのを防ぐために追加されたばかりだと思います。

于 2012-07-25T11:21:17.193 に答える
1

イテレータを使用して要素を削除できるようにしたい場合があります。これは、イテレータを実行するのが最も効率的な方法だからです。たとえば、リンクされたデータ構造(リンクリストなど)をトラバースする場合、イテレータを使用した削除は、操作を介した場合O(1)と比較して、操作です。O(N)List.remove()

そしてもちろん、多くのコレクションは、コレクション中にコレクションを変更する以外の方法でコレクションを変更するように設計されてIterator.remove()ConcurrentModificationExceptionます。


コレクションイテレータを介した変更を許可したくない状況では、イテレータをCollection.unmodifiableXxxx使用してラップし、そのイテレータを使用すると、目的の効果が得られます。あるいは、ApacheCommonsは単純な変更不可能なイテレーターラッパーを提供すると思います。


ちなみに、IEnumerableと同じ「におい」に悩まされていIteratorます。reset()メソッドを見てください。LinkedListまた、C#クラスがO(N)削除の問題をどのように処理するかについても興味がありました。これは、リストの内部を公開することによって行われているようです...値が参照であるプロパティの形式でFirst。これは別の設計原則に違反します...そして(IMO)よりもはるかに危険です。LastLinkedListNodeIterator.remove()

于 2012-07-25T11:19:36.757 に答える
-1

これは実際には Java の素晴らしい機能です。よく知られているように、.NET でリストを繰り返し処理して要素を削除する場合 (多くの使用例があります)、選択肢は 2 つしかありません。

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);
    }
    ...
}

今、私は 2 番目の方法を好みますが、Java ではそのすべては必要ありません。なぜなら、アイテムを使用している間はそれを削除できますが、反復は継続するからです! 正直なところ、場違いに見えるかもしれませんが、実際には多くの点で最適化されています。

于 2012-07-25T11:27:49.450 に答える