今回は引き続き for 文を用いた繰り返しを学びます。 文法的に覚えなければならないことはあまり多くありませんが、 様々な for 文を使い方をマスターし、 繰り返しを用いたプログラムのテクニックを身につけましょう。
繰り返しの途中で強制的に繰り返しから抜け出るためには、 break文を使います。次のプログラムは 1 から 10 までの合計を求めるうちに、 合計値が30を越えたら繰り返しを終了するというものです。
int sum = 0; for (int i = 1; i <= 10; i++) { sum = sum + i; if (sum > 30) break; // sumの値が30を越えたら繰り返しを抜け出す }
繰り返しを中断するもう一つの方法が continue 文です。 break 文がその時点で繰り返しを抜け出すのに対し、 continue 文は、繰り返しの最初に戻ることを行います。
次の for 文は 1から 10 までのうち偶数だけ計算を飛ばす繰り返しです。
int sum = 0; for (int i = 1; i <= 10; i++) { if (i % 2 == 0) continue; // i が 2 で割りきれたらこれ以降の処理を飛ばし、 // 繰り返しの最初に戻る sum = sum + i; }
break文とcontinue文については、教科書では pp.50-51 にまとめられています。
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."); } }
このプログラムは n
が素数か否か判定するプログラムです。
素数とは、1またはその数以外に約数がない (1またはその数でしか割りきれない)
整数のことです。
ファイル名は IsPrime.java としています。
素数かどうかの判定にはいろいろな方法がありますが、
ここでは、 n
を 2, 3, 4, … の順に n
-1 まで割ったとき、
すべての数で割り切れない場合、素数と判定することにします。
このプログラムで注目することは、 次の 2 つ条件を満たしているとき繰り返しをつづけるということです。
n
÷ i
が割り切れない
(すなわち、余りが 0 ではない) 間繰り返す。
割り切れた場合、 n
は素数ではないので、
isPrime
を false
にし、処理を打ち切る。i
を 2 から 1 ずつ増やしていき
i
が n
-1 に達した場合、
n
は 2,3,4,...n-1 のどれとも割り切れなかったことになるので、
素数だと判断し処理を打ち切る。
このプログラムでは 1 つ目の条件を if 文で書き、条件を満たした場合 break 文で繰り返しを抜けるようにしています。 また、 2 つ目の条件を for 文として書き、 条件が成立するまで繰り返しを続けるようにしています。 このように、繰り返しの途中で処理を打ち切りたいケースでは、 break 文を用いると処理の流れを簡潔に記述することができます。
boolean 型の変数 isPrime
は、
素数か否かの結果をいったん入れておく変数です。
最初は true にしておき、素数ではないとわかると
(n
が i
で割りきれると) false にします。
最後の if 文で isPrime
の値によって出力を変えています。
毎時0分, 5分, 10分, ... と 5 分おきに 発車する電車の時刻表を表示するプログラムを考えます。 出力結果は次のようにします。
時 | 発車予定時刻 10 | 0 5 10 15 20 25 30 35 40 45 50 55 11 | 0 5 10 15 20 25 30 35 40 45 50 55 12 | 0 5 10 15 20 25 30 35 40 45 50 55
10, 11, 12 時台のそれぞれについて、0, 5, 10, ... を表示するわけですから、 0, 5, 10, ... という繰り返しを 10,11,12の 3 回行えば良いことがわかります。
class TrainTimeTable { public static void main(String[] srgs) { System.out.println("時 | 発車予定時刻"); for (int hour = 10; hour <= 12; hour++) { System.out.print(hour + " | "); for (int min = 0; min <= 59; min = min + 5) System.out.print(min + " "); System.out.println(); } } }
上のプログラムのように for 文を 2 重に書くと、 外側の繰り返し回数ぶん、内側の繰り返しが実行されます。 今回は、
hour
が 10 のとき
min
が 0min
が 5min
が 10min
が 55 という繰り返しhour
が 11 のとき
min
が 0min
が 5min
が 10min
が 55 という繰り返しhour
が 12 のとき
min
が 0min
が 5min
が 10min
が 55 という繰り返しという繰り返しが行われます。
2つのサイコロの目の和の組み合わせをすべて求めて表示するプログラムを 考えてみましょう。 (話を簡単にするため、 1, 6 の組み合わせと 6, 1 の組み合わせは異なるものとします。)
class SumOfSai { public static void main(String[] args) { for(int i = 1; i <= 6; i++) for(int j = 1; j <= 6; j++) System.out.println(i + " + " + j + " = " + (i + j)); } }
1 から n までの数をカンマ「,」区切りで並べて表示するプログラムを考えます。 例えば n を 10 とすると、次のような出力になります。
1,2,3,4,5,6,7,8,9,10
これまでの例題が理解できた人なら、「10回繰り返せばいいんでしょ? 簡単簡単!」 と思うかもしれません。でもよく見てみましょう。カンマは9個しかありませんよ?
この問題の解答は何通りも考えられますが、 for 文を使って素直に書くと例えば以下のプログラムになります。
class SeparatedByComma1 { public static void main(String[] args) { int n = 10; for(int i = 1; i <= n-1; i++) { System.out.print(i); System.out.print(","); } System.out.print(n); System.out.println(); } }
このプログラムでは、n-1 回目の出力までは数字の後にカンマを出力し、 n 回目だけは数字のみ出力します。
このプログラムは正しく動きますが、問題点が1つあります。 それは、数字を出力する処理 System.out.print(i) が2箇所に存在する点です。 もしプログラムの出力を以下のように変更したくなったとしましょう。
i=1,i=2,i=3,i=4,i=5,i=6,i=7,i=8,i=9,i=10
これは数字を出力する部分を System.out.print("i=" + i)
に変更するだけで実現できるのですが、
2箇所を修正しなくてはならないというのは間違いの原因となります。
「System.out.print("i=" + i)
」を、
もっとずっと複雑な処理 (例えば 100 行) に変更しなければいけないとすると、
そっくりな 100 行のプログラムを 2 回書かなければなりません。
break をうまく使った以下のプログラムでは、方法1の問題点を解決しています。
class SeparatedByComma2 { public static void main(String[] args) { int n = 10; int i = 1; for(;;) { System.out.print(i); if(i == n) break; System.out.print(","); i++; } System.out.println(); } }
for(;;)
は、何もせずひたすら無限に繰り返すということを意味しています。
これでは永久にプログラムは終わらないことになるので、
どこかで break 文を使い、繰り返しを抜け出す必要があります。
さて、プログラムを良く見ると、 数字を出力する System.out.print(i) は1箇所のみとなっています。
この例題では
という処理を繰り返します。
このように、
という繰り返しの場合、 繰り返しの最初で繰り返しの終了条件を判定していたのではうまくいきません。 繰り返しを終了する場所を工夫する必要があります。