インタフェースjava.util.Iteratorは、コレクションを走査するためのものだ。
コレクションには実際にオブジェクトが収められている。
これに対し、順序を持った有限個のデータの集合を生成する規則が与えられれば、
実際にオブジェクトを保有していなくても、メソッドnext()が呼び出される度に
データを生成して返すこともできる。
通常のコレクションである前者を「実コレクション」、
後者を「仮想コレクション」と呼ぶことにしよう。
同じデータを保持しているなら、実コレクションより仮想コレクションの方が
少ないメモリ量で済む。
また、仮想コレクションを走査するIteratorが与えられれば、
next()で得られたオブジェクトをコピーすることで、実コレクションを作ることができる。
従って、計算量を大きく増やさずに仮想コレクションとして提供できるデータならば、
実コレクションとして提供するよりも仮想コレクションとして提供する方が優れている。
仮想コレクションも実コレクション同様、コレクションを表すクラスと
その上を走査するIteratorから成る。
実コレクションはjava.lang.Iterableを実装し、メソッドiterator()を持つ。
仮想コレクションも新規のIteratorを返すメソッドiterator()を持つ。
仮想コレクションではnext()の際、新しいインスタンスを作る必要が無い。
同じオブジェクトの内容を書き換えれば十分だ。
next()を呼び出した側がオブジェクトを書き換えたければ、
そこでコピーして書き換えればいい。
この書き換えるオブジェクトのことをトレイ(tray)と呼ぼう。
iterator()によって新規のIteratorのインスタンスを作る際には、
複数のスレッドで走査することを可能にするため、
トレイを新しく作る必要がある。
以上の考察をまとめると:
+ 仮想コレクションはデータを生成する規則への入力パラメータを保持し、
新規のIteratorを返すメソッドiterator()を持つ。
+ メソッドiterator()は新しいIteratorを生成する。
このIteratorはトレイを持つ。
+ Iteratorはメソッドnext()の度にトレイの内容を更新する。
このような仮想コレクションの基本的なものとして、トレイがint[]型のものを考える。
N重ループに相当するイテレータや、N桁のn進数を順に返すイテレータが、
長さNの配列で実装できる。
トレイをint[]にする場合、必ずしも全要素を使うは必要なく、
first番からn個の範囲を使うようにすることができる。
これらを利用者が指定できるようにするには、
メソッドの引数にしてiterator(int[], int, int): Iteratorとする。
これにより、インタフェースIterableIntegerArrayを定めることができる。
これはただひとつのメソッドiterator(int[], int, int): Iteratorを持つ。
この場合、トレイへの参照は呼び出し側が初めから持っているから、
Iteratorのメソッドnext()はトレイを返す必要が無い。
代わりにより有用な情報として、次のデータが本来何番目のデータなのかを
返すようにできる。
メソッドremove()が何もしない場合には、
これはもちろんforループにカウンタを付ければ済む。
だが、メソッドremove()がその意味通りに実装される場合には、
本来何番目かという情報は意義を持つ。
データは規則によって生成されているので、
データの内容だけから何番目かを求めることは出来る。
とはいえ、その計算はIterator内で行う方が簡単である。
こうしたことから、インタフェースIterableIntegerArrayのIteratorの
メソッドnext()はjava.lang.Integerを返すことにする。
つまり、Iterator<Integer>となる。
まとめ