プログラムには、文を何回も繰り返す機能があります。 これまで、似たような処理を何回も書かなければならない例題や、 演習問題がありましたが、 繰り返しの機能を使うと簡潔に書くことができます。
繰り返しを用いたプログラムの書き方として、 今回は for 文を取り上げます。
for 文の文法的な説明は、教科書 pp.46-47 を参照してください。
for文の文法についてまとめてみましょう。
for 文は繰り返しの前に、式1 を一回だけ実行します。 これは、繰り返しの前の準備作業と言えます。 通常、ここには変数への初期値の代入など、初期化処理を書きます。
式2 は、繰り返しを続けるかどうかの判断を表す式を書きます。 式2 の条件が満たされている間繰り返しを行います。
式3 は、繰り返しを1回実行したあとに次の回に進めるための操作を書きます。 通常は、繰り返しの次の回に移る際に変数の値を変化させる操作等を行います。
また、式1 〜式3 は、いずれも省略することができます。 ただし、セミコロン (;) は省略できません。 式1 や式3 を省略した場合単に何もしないことになるのですが、 式2 を省略すると無限に繰り返しを行うことになります。 この場合は別の方法で、繰り返しを止めるようにしなければなりません。
for文の典型的な使い方は以下のようなプログラムです。
class OneTwoThree { public static void main(String[] args) { int i; for (i = 1; i <= 3; i++) { System.out.println("iの値は " + i + "です"); } } }
繰り返しを用いたプログラムでは、 文法的な知識として覚えることはそれほど多くありません。 それよりも、プログラムの書き方についての感覚をつかむことの方が重要です。 また、変数をどう使えば良いかも要点になります。 ここでは、プログラムの例を読むことによって、 繰り返しを使ったプログラミングの感覚をつかみましょう。
繰り返しのあるプログラムはプログラムの同じ場所を 何回も実行することになります。 同じ場所を通るたびに変数の値が少しずつ変わり、 最終的に結果が求まります。 ここで、各変数の値はある規則にしたがって変化していくことを きちんと理解する必要があります。
次の例題を用いて、プログラムの理解の仕方を説明しましょう。 プログラムの名前は SumOneToThree としています。
class SumOneToThree { public static void main (String[] args) { int sum = 0; int i; for (i = 1; i <= 3; i++) { sum = sum + i; } System.out.println("1 から 3 までの和は " + sum); } }
このプログラムは 1 から 3 までの和を求めて表示するものです。 結果は 6 となります。
まず、下の下線の部分に注目してみましょう。
for (i = 1; i <= 3; i++) { sum = sum + i; }
この繰り返しのための準備を行う式は i = 1 です。 繰り返しは、「変数 i が 1」から始まることになります。
次の i <= 3 は、 この for 文の繰り返しを続けるかどうかの条件です。 i <= 3 を満たしている間、すなわち「i が 3 以下のとき」 繰り返しを続けることになります。
さらに次の、 i++ は、繰り返しの中身を 1 回実行したあとに 次の回に進めるための式です。 この場合、「繰り返し 1 回ごとに i を 1 増やす、」 ということを行います。
以上から、この for 文は 「i が 1 から 3 まで 1 ずつ増えながら 3 回の繰り返しを行う。」 と解釈することができます。
次に、for 文の中身に注目します。
for (i = 1; i <= 3; i++) { sum = sum + i; }
for の中身 sum = sum + i は、 繰り返しの毎回で行う計算の内容です。
繰り返しの中身の動きを追ってみましょう。 繰り返しは i が 1,2,3 と変化しながら 3 回行われるわけですから、 sum の式によって変数の値は次のように変化します。
初期値: sum = 0 , i = 1 1回目: sum = sum ←(0) + i ←(1) → iは1 sumは1 i++ 2回目: sum = sum ←(1) + i ←(2) → iは2 sumは3 i++ 3回目: sum = sum ←(3) + i ←(3) → iは3 sumは6 i++ ここで i <=3 を満たさなくなるので繰り返しは終了 1から3までの合計が計算できた
このようなトレースは最も単純で明快な方法と言えます。 例を使ってプログラムを理解する方法は、初心者には一番分かりやすいでしょう。 しかし、プログラムが複雑になり多数の変数や条件が絡み合ってくると、 この方法での理解は限界があります。
プログラムの理解の鍵は、変数の意味をしっかり把握することです。 「プログラムのこの地点では、この変数にこういう値が入っている。」 と言えるようにするのです。たとえば、x, y, z の最大値を求めるプログラムも、 この原則を適用すると理解の助けになるはずです。
例題のプログラムでは、繰り返しの中に 2 つの変数 i と sum が現れます。 変数 i は 1 から 3 まで 1 ずつ増えていきます。 これはすぐに分かります。 1 から 3 までの和を求めるのですから、 1 から 3 までの値を 1 回ずつ登場させるのは当然です。
変数 sum の方はどうでしょう。 「sum の値は 1 から i までの和が入っている。」 と説明できます。
以上から、この繰り返しでは、 「i を 1 ずつ増やしながら途中までの和を求め、 その値を sum に代入している。」と説明することができます。
厳密には、sum = sum + i が実行された直後の sum は 1 から i までの和で、 繰り返しの中身が終わった段階 (i <= 3 の判定が行われる段階) では、 sum は 1 から i-1 までの和です。 また、少し考えると for 文から抜けたときの i の値は、 4 であったことがわかります。 ここでも sum が 1 から i-1 の和という意味が成立しています。 i を 4 で置き換えると、 最終的には sum は 1 から 3 までの和ということになり、 所期の目的が達成できていることが分かります。
このように、変数に入っている値の意味を言葉で言えるようにすることが重要です。 プログラムを書くときは、この考え方を逆に利用します。 最初に、プログラムのある地点で、 変数にこんな意味の値が入っているようにしようと決め、 その値を変数に入れるにはどんな計算をすれば良いかを考えるのです。
前の例題は変数 i が 1 から 1 刻みに増える for 文でした。 次のような for 文も考えられます。
for (i = 0; i < 10; i++)
for (i = 0; i < 10; i = i + 2)
for (i = 10; i > 0; i--)
for (i = 0; i < n; i++)
これまで示したプログラムでは、冒頭で変数宣言を行っていました。 実は、 Java ではプログラムの任意の位置で変数宣言を行うことができます。 例えば、次のような for 文を書くこともできます。
for (int i = 0; i < 10; i++) ....
ただし、プログラムのどこからでも変数が使えるわけではありません。 変数は、宣言したもっとも近い中カッコの範囲内でのみ有効です。 中カッコの範囲内のことをブロックと呼び、 変数の有効範囲のことをスコープと呼びます。
例えば for 文の中カッコの内側で宣言した変数は、 繰り返しの外では使うことができません。 次は間違いの例です。
for (int i = 0; i < 5; i++) { int sum = sum + i; } System.out.println("合計は " + sum);
変数 sum は for 文の中カッコ内で宣言されているため、 その外側で使うことはできません。正しくは sum を for 文の外側で宣言し、 次のように書きます。
int sum = 0; for (int i = 0; i < 5; i++) { sum = sum + i; } System.out.println("合計は " + sum);
変数宣言を行う際には、どの変数がどういう意味で使われているか 把握しやすい位置で宣言すると良いでしょう。 例えば、その変数を使う直前で宣言するようにしたり、 あるまとまった処理についての変数であれば、 その処理の冒頭に変数宣言をまとめておく等の方針が良いでしょう。
for 文も if 文も「文」の一種です。 また、繰り返しの中身や条件判定の中身に書くことができるのも「文」です。 したがって、これまで学んだ、for 文、 if 文、式文、変数宣言式文などは すべて自由に組み合わせることができます。
class SumOfEvenNumbers2 { public static void main(String[] args) { int n = 10; int sum = 0; for (int i = 0; i <= n; i++) if (i % 2 == 0) { sum = sum + i; System.out.println("0 から " + i + " までの偶数の合計は " + sum); } } }
Java では四則演算のような計算以外にも、 多くのものを「式」として扱います。 式は数値や文字や、条件が成り立つ/成り立たないなどの 何らかの値を持っています。
例えば、次のようなものはすべて式です。
1 a + b "Hello world." "max = " + a a > 5 && a == b a = 1
実は if 文や for 文に書く条件や代入も式の一種なのです。 for 文のカッコの中には 3 つ式を書くわけですが、 代入をその一つとして書けるのは、 Java が代入を式として扱っているからです。
Java における式の演算子にどのような種類があるのかは、 教科書 pp.36-37 にまとめてあります。 ここで、優先順位が高い演算子とは、 他の演算子より先に計算が行われるという意味です。
教科書 pp.28 も同時に参照してください。
if 文や for 文で使われる条件式は、 ある条件が成り立つか成り立たないかを判定する式でした。 この「成り立つか成り立たないか」という真偽そのものも変数に 入れておくことができます。
例えば、次の式は x が正であるという条件を満たしているか、 満たしていないか、言わば Yes か No かという値を condition に代入しています。
condition = x > 0;
condition に入る Yes か No かという値は、 Javaでは true (真、すなわち条件が成立している) と false (偽、すなわち条件が成立していない) という値をとることになっています。
そして、 true か false かという値は boolean 型の変数に入れておくことができます。
boolean condition1; boolean condition2; condition1 = x == y; condition2 = y == z; if (condition1 && condition2) { // x と y が等しい、かつ y と z が等しい }
boolean 型の変数は、 場合わけのための目印のような役割をさせることもできます。 以下は、1898年から1903年までにうるう年が あったかどうかを判定するプログラムです。
class LeapYearSearcher { public static void main(String[] args) { boolean isLeapYear = false; // うるう年があったかどうかを示す目印 for(int i = 1898; i <= 1903; i++) if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) isLeapYear = true; // 繰り返し中にうるう年が一つでもあったら true にする if (isLeapYear) System.out.println("うるう年がありました"); else System.out.println("うるう年がありませんでした"); } }
代入のイコールも演算子の一つなので、 式の中の要素として書くことができます。 例えば、
w = x + (y = z + 1);
などという式を書くことができます。 この式の意味は、 y に z + 1 を代入して、 その値に x を加えたものを w に代入する、という意味です。 代入の式 (y = z + 1) 自身も値を持っており、 それは z + 1 の値になります。
このような書き方をすると、複雑な式を簡潔に書けることがあります。 例えば、以下のようなプログラム片、
if ((x = y - 1) == 0 ) ....
は、y - 1 の値を x に代入し、 その値が 0 であれば if 文の中身を実行する、ということを示しています。
ただし、初心者にはこの書き方はあまり勧められません。 プログラムが分かりにくくなり、間違いを犯す可能性が増えるからです。 最初は、なるべく単純な書き方でプログラムを書くようにする方が良いでしょう。