Iterator
「無限」の実装、つまりhasNext()
always(*) の呼び出しが true を返す実装を提供することは、一般的に悪い習慣だと考えられていますか?
通常、呼び出しコードが不規則に動作する可能性があるため「はい」と答えますが、以下の実装では、hasNext()
呼び出し元がイテレータが初期化されたリストからすべての要素を削除しない限り、trueを返します。つまり、終了条件があるこれは の正当な使用法だと思いますかIterator
? 直感に反すると主張する人もいるかもしれませんが、契約に違反しているようには思えません。
public class CyclicIterator<T> implements Iterator<T> {
private final List<T> l;
private Iterator<T> it;
public CyclicIterator<T>(List<T> l) {
this.l = l;
this.it = l.iterator();
}
public boolean hasNext() {
return !l.isEmpty();
}
public T next() {
T ret;
if (!hasNext()) {
throw new NoSuchElementException();
} else if (it.hasNext()) {
ret = it.next();
} else {
it = l.iterator();
ret = it.next();
}
return ret;
}
public void remove() {
it.remove();
}
}
(衒学的)編集
Iterator
フィボナッチ数列などの無限数列から値を生成するために Iterator をどのように使用できるかについてコメントする人もいます。ただし、JavaIterator
ドキュメントでは Iterator について次のように説明されています。
コレクションの反復子。
java.util.Collection
フィボナッチ数列は無限コレクションであると主張することもできますが、Java ではコレクションを、コレクションが制限付きでなければならないことを暗示するなどのメソッドを提供するインターフェースと同一視します。したがって、制限なしのシーケンスから値を生成するジェネレーターとしてsize()
使用することは正当でしょうか?Iterator
ベストアンサー1
それはそうですね完全に合法- はIterator
単なる「もの」のストリームです。ストリームはなぜ必ず境界を定める必要があるのでしょうか?
他の多くの言語(例えばScala)には、無制限のストリームの概念が組み込まれており、これらを反復処理することができます。例えば、scalazを使用すると
scala> val fibs = (0, 1).iterate[Stream](t2 => t2._2 -> (t2._1 + t2._2)).map(_._1).iterator
fibs: Iterator[Int] = non-empty iterator
scala> fibs.take(10).mkString(", ") //first 10 fibonnacci numbers
res0: String = 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
編集: 驚きを最小にする原則に関しては、完全にコンテキストに依存すると思います。たとえば、このメソッドが返す結果は何になると思いますか?
public Iterator<Integer> fibonacciSequence();