繰り返しにはいくつかの書き方がありますが、 今回は while 文をとりあげます。
while 文の文法的な説明は 教科書pp.144〜149のとおりです。
文法的には、while文はfor文よりも単純です。 条件式が成立する限り中身を繰り返し続ける、というだけです。 for文のように初期化、条件、差分といった枠組みがないため 自由度の高い繰り返しを書くことが可能ですが、 変数の意味や値の変化の仕方などの繰り返しの構造を、 よりきちんと理解しておく必要があります。
下のプログラムはwhile文のシンプルな例です。
int i = 0; while (i < 3) { 処理 }
変数 i が 3 より小さい間「処理」を繰り返します。 繰り返しの中で、i が変化しなければ、 永久に「処理」を繰り返し繰り返すことになってしまいます。 そこで「処理」の中には、 例えば次のように、 i を変化させるようなプログラムを書くことになります。
int i = 0; while (i < 3) { 処理 i++; }
上のプログラムで行っていることは、 for文を使うと次のように書くことができます。 for文とwhile文の文法を比較しましょう。
for (int i = 0; i < 3; i++) { 処理 }
for文の例題でとりあげた、 1からnまでの合計を求めるプログラムをwhile文で書くことを考えてみましょう。 for文を用いると次のように書くことができました。
class SumOneToThree { public static void main(String[] args) { int sum = 0; for (int i = 1; i <= 3; i++) { sum = sum + i; } System.out.println("1 から 3 までの和は " + sum); } }
このプログラムをwhile文を使って書き換えると以下のようになります。 繰り返しの制御に関係する下線部分に注目しましょう。
class SumOneToThree2 { public static void main(String[] args) { int sum = 0; int i = 1; while (i <= 3) { sum = sum + i; i++; } System.out.println("1 から 3 までの和は " + sum); } }
for文の回の例題をwhile文を使って書き換えてみましょう。 for文を使ったプログラムは次のようなものでした。
class IsPrime { public static void main(String[] args) { int n = 31; boolean isPrime = true; for (int i = 2; i <= n - 1; i++) { if (n % i == 0) { isPrime = false; break; } } if (isPrime) System.out.println(n + " is a prime number."); else System.out.println(n + " is not a prime number."); } }while文を使って書き換えると次のようになります。
class IsPrime2 { public static void main (String[] args) { int n = 31; boolean isPrime = true; int i = 2; while (i <= n - 1) { if (n % i == 0) { isPrime = false; break; } i++; } if (isPrime) System.out.println(n + " is a prime number."); else System.out.println(n + " is not a prime number."); } }
1+2+3+ ... +n の和を計算し、 和が100を越えた時点で終了するプログラムを考えてみましょう。
class SumUntil100 { public static void main(String[] args) { int sum = 0; int i = 1; while (sum <= 100) { sum = sum + i; i++; } System.out.println("1 から " + (i-1) + " までの和は " + sum); } }
このプログラムのポイントは、 繰り返しを続けるための条件が繰り返しの回数ではなく、 変数 sum の値であるということです。 i は繰り返しを続けるかどうかの判断には関係がなく、 単に 1 刻みに数を数える役割しかありません。
例えば、次のプログラムについて考えてみましょう。
int sum = 0; for (int i = 1; i <= n; i++) sum = sum + i;
このプログラムの働きは 1 から n までの和を求めることです。 また、while 文を用いた同じ働きをするプログラムは次のとおりです。
int sum = 0; int i = 1; while (i <= n) { sum = sum + i; i++; }
2つのプログラムを見比べてみると、 「i を 1 から n まで 1 ずつ増やしながら繰り返す」 という論理を分かりやすく表しているのは for 文の方です。
while 文の方は、i++; が離れた位置にある (この場合はわずか 2 行ですが、 一般にはもっと離れることが多いのです) ので、 繰り返しに関係がある処理がどこにあるかを見分けることが難しくなります。 また、sum = 0; や sum = sum + iが繰り返しの中身の仕事であり、 一方、i = 1; や i++; が繰り返しの制御に関係している、 ということを一目で見抜くことは難しいと言えます。
このように、for文が適当なケースとは、 あらかじめ繰り返す回数が決まっているような場合であると言えるでしょう。 例えば、 1, 2, 3, ..., 100 の順に値を代入しながら繰り返すといった場合には 適していると言えます。
一方、上の例題でとりあげたような、 繰り返しの中で行う処理の結果によって繰り返すか、 打ち切るかを決めるようなケースでは、while 文の方が適当だと言えます。
さまざまなプログラムの読み書きを経験し、 これらの使い分けのテクニックを身につけるのです。
y = x2 のグラフを描きます。 ただし、普通のグラフの描き方を 90 度回転したものです。 グラフのようなものはグラフィック表示にすることが望ましいのですが、 今のところ文字による表示法しか学んでいません。 そこで、文字を並べることによってグラフらしきものを表示することにします。
このプログラムのファイル名は Graph.java としています。
class GraphWithFor { public static void main(String[] args) { for (int x = -8; x <= 8; x++) { int y = x * x; for (int i = 0; i < y; i++) System.out.print(" "); System.out.println("*"); } } }
class Graph { public static void main(String[] args) { int x = -8; while (x <= 8) { int y = x * x; int i = 0; while (i < y) { System.out.print(" "); i++; } System.out.println("*"); x++; } } }
このプログラムは繰り返しが二重になっています。 while 文の中に while 文が、 あるいは for 文の中に for 文が含まれています。
外側の繰り返しでは、 x の値を -8 から 8 まで 1 ずつ増やしながら繰り返します。 x の値が 9 になったら繰り返しを終了します。
内側の繰り返しでは、 i が y より小さい間、 i の値を 0 から 1 ずつ増やしていき、 i が y と等しくなった時点で終了になります。 例えば y の値が 3 だったとき、 i の値は 0, 1, 2 と増えていき 3 になった時点で終了します。 要するに、この繰り返しの中身を y の値と同じ回数だけ繰り返すということです。
この繰り返しのたびに System.out.print(" ") を実行しているので、 y の値の数と同じ個数の空白を出力することになります。 これによって、繰り返しが終った後に表示している * は、 画面左端からの距離が y の位置に表示されます。 * の表示には System.out.println を用いているため改行されるので、 x を 1 増やしたときの y の値に相当する * は、 次の行に表示されるようになります。