1.1. while ループより for ループ
『目的』
ループの書き方を変えてコピー&ペーストによるバグを事前に見つけましょう。
『Before』
繰り返し回数が決まっているものは『forループ』、条件を満たしている間繰り返すのは『whileループ』、と使い分けていることが多いと思います。
これは『whileループ』による繰り返しの例です。
イテレータのループ変数「i」の要素が存在している間、処理を繰り返します。
Iterator i = c.iterator;
while (i.hasNext()) {
doHoge(i.next());
}
/* 以後、変数 i は使わない。 */
// :
通常この場合、ループから抜けた後は変数「i」を使うことはありませんよね。
ところで、似たようなコードを書く時にコピー&ペーストをすることはよくあると思います。
下の例をご覧ください。
1つ目のループのコードをコピー&ペーストして2つ目のループを書いています。
Iterator i = c.iterator;
while (i.hasNext()) {
doHoge(i.next());
}
// :
Iterator i2 = c2.iterator;
while (i.hasNext()) { /* i.hasNext() は誤り! */
doHoge(i2.next());
}
コピー&ペーストした後、2つ目のループの条件文で正しい変数名に直すことを忘れたため間違いが起きています。変数「i」を使っていることがミスであり実装として不具合なのですが、コンパイラレベルでは正常なので誤りに気づきません。
こういったことって、意外と起こりやすいものです。
『After』
ループ変数の内容がループ終了後に不要なのであれば、『whileループ』ではなく『forループ』を使っても同じ処理が行えます。
for (Iterator i = c.iterator; i.hasNext(); ) {
doHoge(i.next());
}
先ほどと同様の間違いがあった場合どうでしょう。
for (Iterator i = c.iterator; i.hasNext(); ) {
doHoge(i.next());
}
// :
for (Iterator i2 = c2.iterator; i.hasNext(); ) { /* i.hasNext() は誤り! */
doHoge(i2.next());
}
コンパイルしようとすると、変数「i」が宣言されていないという理由でエラーが検知されます。
では、間違えている箇所を直しましょう。
for (Iterator i = c.iterator; i.hasNext(); ) {
doHoge(i.next());
}
// :
for (Iterator i2 = c2.iterator; i2.hasNext(); ) {/* i.hasNext() を i2.hasNext() に修正。*/
doHoge(i2.next());
}
でも、ループ変数「i」と「i2」は各々の『forループ』の中だけでしか利用されていませんので、「i」と「i2」は同じ名前でも何ら問題はありません。
以下のようにするのがより良いでしょう。
for (Iterator i = c.iterator; i.hasNext(); ) {
doHoge(i.next());
}
// :
for (Iterator i = c2.iterator; i.hasNext(); ) { /* i2 を i に書き換える。*/
doHoge(i.next());
}
『まとめ』
ループ変数のスコープを『forループ』内に限定することで、変数名の直し忘れをコンパイラが認識し、エラーを検知してくれます。それによってバグの原因を気づかせてくれるのです。
コンパイラは頼もしい味方です。