強化版の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コレクション反復メカニズムを作り出し、そのたびに改良を加えました。近い将来、また新しいメカニズムが登場することは間違いないでしょう。
