強化版のforを試す
強化版のfor
ループはとても便利です。コードが簡潔になると同時に表現力も向上するので、申し分なしです。ただし、まだ足りない部分もあります。数字の0から9まで処理を反復するとしたら、古いCスタイルのfor
ループ構文をいまだに使う必要があります。
for (int i = 0; i < 9; i++) ...
では、この範囲を新しい抽象表現にしてみたらどうでしょうか。
Sequence s = new Sequence(0, 9);
このSequence
クラスにIterable
<Integer
>を実装しておけば、強化版のfor
ループで次の記述が可能になります。
for (int i: new Sequence(0, 9)) ...
オートアンボクシングが追加されたため、クライアントインターフェースは非常に簡潔になります。リスト1に、Sequence
クラスの完全なコードを示します。
import java.util.Iterator; public class Sequence implements Iterable<Integer> { private int start; private int stop; private int increment = 1; public Sequence(int start, int stop) { this.start = start; this.stop = stop; } public Sequence(int start, int stop, int increment) { this(start, stop); this.increment = increment; } public Iterator<Integer> iterator() { return new SequenceIterator(); } private class SequenceIterator implements Iterator<Integer> { private int count = start; public boolean hasNext() { return count <= stop; } public Integer next() { int result = count; count += increment; return result; } public void remove() { throw new UnsupportedOperationException(); } } }
このSequence
クラスには、要素をスキップする機能もあります。Sequence
クラスのさまざまな使用例をリスト2に示します。
import static org.junit.Assert.*; import org.junit.*; import java.util.*; public class SequenceTest { private List<Integer> ints; @Before public void createCollection() { ints = new ArrayList<Integer>(); } @Test public void singleEntry() { verifySequence(new Sequence(0, 0), 0); } @Test public void twoEntries() { verifySequence(new Sequence(1, 2), 1, 2); } @Test public void multipleEntries() { verifySequence(new Sequence(5, 10), 5, 6, 7, 8, 9, 10); } @Test public void negativeNumbers() { verifySequence(new Sequence(-2, 2), -2, -1, 0, 1, 2); } @Test public void increment() { verifySequence(new Sequence(0, 5, 2), 0, 2, 4); } @Test public void incrementIncludesLimit() { verifySequence(new Sequence(0, 6, 2), 0, 2, 4, 6); } private void verifySequence(Sequence sequence, int... expectedValues) { for (int i: sequence) ints.add(i); assertEquals(expectedValues.length, ints.size()); for (int i: expectedValues) assertTrue(ints.contains(i)); } }
どこにメリットがあるのでしょうか?まず、コードが簡潔になります。また、Sequence
がオブジェクトであることに利点があります。シーケンスを受け渡す(そして永続化する)ことができるのです。範囲やその他の情報を表す具体的な数字(ステップ値など)を受け渡さなければならないのとは大違いです。また、シーケンスを使用するコードを変更せずに機能を拡張できます。例えば、シーケンスを一時停止し、後でその位置から再開することもできるでしょう。
反復は、ありふれたコンピューティング処理の1つです。簡潔で、なおかつ一貫性と表現力のある実装方法が求められる状況には、反復はまさにうってつけです。Sunはこれまでに三度にわたってJavaコレクション反復メカニズムを作り出し、そのたびに改良を加えました。近い将来、また新しいメカニズムが登場することは間違いないでしょう。