|
|
繰り返し処理 |
H.Kamifuji . |
ここでは同じ処理を一部だけ変化させながら繰り返し行う方法を確認します。具体的にはJavaで用意されているfor文やwhile文の使い方を学習していきます。 当ページでは、Linux CentOS7 の Gnome で動作テストしています。 現在(2021/08)では、JDK-16.0.2 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2021/11)では、JDK-17.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2023/04)では、JDK-20.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2024/10)では、JDK-23 にアップされています。一部、上位互換について、見直しを行っていきます。 |
|
まずは繰り返し処理がどういった時に使われるのかを簡単に確認してみます。 例えば1から10までの数を順に足した結果を求めるプログラムを作成してみます。 int sum = 0; sum += 1; sum += 2; sum += 3; sum += 4; sum += 5; sum += 6; sum += 7; sum += 8; sum += 9; sum += 10; System.out.println("合計は" + sum + "です");このように1つ1つ処理を記述していくことも可能ですが、1から10ではなく1から1000までの数を加算した結果を求めることになると一つ一つ足していくのは現実的ではありません(もちろん公式などを使って計算することも可能ですがここではそれは考えていません)。 同じ処理を何度も繰り返す場合や条件を少しずつ変えて指定の回数だけ同じような処理を繰り返す場合にはfor文やwhile文を使うことで簡潔にプログラムを記述することができます。詳細な使い方は次のページ以降で解説しますが、先ほど例をfor文を使った書き直すと次のようになります。 int sum = 0; for (int i = 1; i <= 10; i++){ sum += i; } System.out.println("合計は" + sum + "です");1つ1つ記述したいた加算の部分をfor文を使って記述しています。これを1から1000まで加算するプログラムに変更するには次のように1箇所だけ変更するだけです。 int sum = 0; for (int i = 1; i <= 1000 ; i++){ sum += i; } System.out.println("合計は" + sum + "です");繰り返し処理を適切に使うことでプログラムを非常に簡潔に記述できる場合があることがお分かり頂けたかと思います。では次項のページから順に繰り返し処理の使い方を確認していきます。 では先ほど掲載した例を実際に試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample1_1{ public static void main(String args[]){ int sum = 0; for (int i = 1; i <= 1000; i++){ sum += i; } System.out.println("合計は" + sum + "です"); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample1_1 合計は500500です [xxxxxxxx@dddddddddd For]$ |
まず最初のfor文について確認します。for文は指定した回数だけ処理を繰り返す時に使われます。書式は次の通りです。 for (初期化式; 条件式; 変化式){ 実行する文1; 実行する文2; ... }for文では条件式を評価しtrueだった場合には「{」から「}」のブロック内に記述された文を実行します。条件式は関係演算子及び論理演算子などを使って記述します。(関係演算子及び論理演算子を参照して下さい)。 そしてブロック内の処理が一通り終わると改めて条件式を評価します。そしてまたtrueだった場合にはブロック内の文の実行し、falseだった場合にはfor文を終了します。 なお繰り返しで実行される文が一つだった場合には「{」と「}」を省略して次のように記述することもできます。 for (初期化式; 条件式; 変化式) 実行する文;ではまず条件式だけを使ってfor文を記述してみます。次の例を見て下さい。 int sum = 0; int count = 0; for (; count < 2;) { sum += 2; count++; } System.out.println(sum);この例では条件式「count < 2」がtrueとなる間繰り返し処理を実行します。繰り返し処理を1度実行するために条件を変化させなければ無限に繰り返しを行ってしまいますので今回の例では繰り返しの中で実行される文の一つとして変数「count」の値を1ずつ増加させています。 この例では次のように文が実行されていきます。 1)sum = 0; 2)count = 0; 3)条件式を評価。countは2よりも小さいので繰り返しを実行 4)sum += 2; 5)count++; 6)条件式を評価。countは2よりも小さいので繰り返しを実行 7)sum += 2; 8)count++; 9)条件式を評価。countは2よりも小さくないので繰り返しを終了 10)System.out.println(sum);このようにfor文ではまず最初に条件式が評価されます。もしも条件式がいきなりfalseとなった場合には繰り返し処理は実行されません。条件式がtrueだった場合にはfor文の「{」から「}」までのブロック内の文を順に実行していきます。 ブロック内の最後の文を実行したら1回目の繰り返しが終了です。そしてfor文の最初に戻り改めて条件式を評価します。trueなら再度ブロック内の文を実行し、falseだった場合にはfor文の次の文へ処理が移ります。 for文はこのように条件式の評価とブロック内の処理の実行を繰り返す為のものです。 初期化式と変化式for文では条件式の他に初期化式と変化式を記述することができます。初期化式に記述した式はfor文で最初に条件式が評価される前に一度だけ実行されます。使い道としてはfor文の条件式で使用される変数の宣言と初期化に利用されることが多いです。for文の条件式で使用する回数をカウントするための変数について、最初の例では変数の宣言と初期化をfor文の外でで行っていましたが初期化式の箇所で記述することができます。 変化式は繰り返し処理が一度終わるたびに実行される式を記述します。主に条件式で使われている変数の値を変化させるための式を記述します。例えば条件式で使用している変数の値を1つ増加させるような式を記述します。 では先ほどの例を書き直してみます。 int sum = 0; for (int count = 0; count < 2 ; count++){ sum += 2; } System.out.println(sum);先ほどと比べて、for文の条件式で使用する変数はfor文で宣言と初期化が行われており、また繰り返しが行われるたびに何をどう変化させるのかが変化式の箇所に書かれていて明確になっています。 では基本的な使い方をご紹介しておきます。n回繰り返し処理を行う場合は次のように記述します。 for (int i = 0; i < n; i++){ /* 実行する文 */ }例えば3回繰り返す時は「n」のところに3と記述し、10回繰り返し場合は「n」のところに10と記述します。10回の場合で言えば変数「i」の値は0から9の間は繰り返しを実行し、10になった時には条件式がfalseとなりfor文が終了します。結果的に繰り返しは10回行われます。これは次のように記述しても同じです。 for (int i = 1 ; i <= n ; i++){ /* 実行する文 */ }この場合は変数「i」が1から10の間は繰り返しを実行し、11になった時に終了します。この場合でも繰り返しは10回実行されます。変数の値を条件式での評価だけではなく繰り返し処理の中で使用したい場合などには回数だけではなく、数値を何から何まで変化させて回数を計算するのかも考えなくてはなりません。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample2_1{ public static void main(String args[]){ int sum = 0; for (int i = 0; i < 10; i++){ sum += 2; } System.out.println(sum); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample2_1 20 [xxxxxxxx@dddddddddd For]$繰り返し処理は10回行われており、1回毎に数値に2を加算しているため結果は20となります。 |
for文は決められた回数だけ繰り返し処理を行うのによく使用される文です。その為、繰り返しを継続するかどうかは回数をカウントするための変数を使って行うことが多くなります。ここではこの変数を値を利用する方法を確認します。 例として11から15までの数値を画面に表示するプログラムを考えてみます。 int num = 11; for (int i = 0; i < 5; i++){ System.out.println(num); num++; }表示する数値を保存するための変数「num」を用意し、for文のブロック内で変数「num」の値を表示した後で1つ増加させています。そしてfor文で5回繰り返しを行っています。 このような場合、for文の条件式で使用している変数を利用することができます。条件式の変数はfor文のブロック内で値を取り出すことができます。では先ほどのサンプルを次のように書き換えてみます。 for (int i = 11; i <= 15; i++){ System.out.println(i); }今回のサンプルでは変数「i」が11から15まで1ずつ増加しながらブロック内の処理を実行しています。ブロック内では変数「i」の値を取得して画面に出力しています。 このようにfor文の条件式で使用する変数はブロック内でも利用できますので、初期値と条件式をうまく設定することでよりプログラムを簡潔に記述することができます。 次のサンプルでは数値を5から1まで1つずつ減らしながら値を画面に出力しています。 for (int i = 5; i <= 1; i--){ System.out.println(i); }今までのサンプルでは変化式で変数の値を1だけ増加させていましたが、今度は1だけ減らすようにしています。 次のサンプルでは数値を20以下の3の倍数を順に画面に出力しています。 for (int i = 3; i <= 100; i += 3){ System.out.println(i); } for文のブロック内で宣言した変数を扱う時の注意点for文の初期化式などfor文のブロック内で宣言した変数を利用する時には注意すべきことがあります。次の例を見て下さい。for (int i = 0; i < 5; i++){ /* ブロック内の処理 */ } System.out.println(i);for文が終わった後でfor文の中で宣言した変数の値を画面に出力しています。このサンプルはコンパイルの時点でエラーとなります。 これはブロック内で宣言した変数はブロックの外に出てしまうと使用することができないためです。逆にブロックの外で宣言した変数はブロック内でも使用できます。次の例を見てください。 int a = 0; for (int b = 0 ; ; ){ System.out.println(a) // 変数a は利用可能 System.out.println(b) // 変数b は利用可能 } System.out.println(a) // 変数a は利用可能 System.out.println(b) // 変数b は利用不可このように変数が宣言された位置によってどこでその変数を利用できるのかが決まります。これを変数のスコープ(有効範囲)などと読んだりしますが、ここではブロック内で宣言した変数はブロックが終わると使えなくなるとだけ覚えておいて下さい。 よってfor文の中で使用した変数の値をfor文が終わった後でも使用したい場合には、変数の宣言はfor文の外で行うことで可能となります。 int i; for (i = 0; i < 5; i++){ /* ブロック内の処理 */ } System.out.println(i);今回は初期化式を例にしましたが、for文のブロック内で変数を宣言した場合も同じです。ブロックがプログラムの中で使われる場合には、変数がどこで宣言されたものか注意するようにして下さい。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample3_1{ public static void main(String args[]){ int i; for (i = 3; i <= 20; i += 3){ System.out.println(i); } System.out.println("変数の値が" + i + "で条件式がfalseとなりました"); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample3_1 3 6 9 12 15 18 変数の値が21で条件式がfalseとなりました [xxxxxxxx@dddddddddd For]$ |
for文では初期化式、条件式、変化式の3つの式を使用しますが、初期化式と変化式には複数の式を記述することができます。複数の式を記述する場合は式と式の間をカンマ(,)で区切って記述します。 for (初期化式1, 初期化式2, ..; 条件式; 変化式1, 変化式2, ..){ 実行する文; }※条件式は関係演算子と論理演算子で複雑な条件式を記述できます。 例えば次の例を見て下さい。 int i, j; for (i = 1, j = 9; i < 10; i++, j--){ System.out.println("i = " + i + ",j = " + j); }この例では初期化式で変数「i」と「j」の初期値を設定しています。また変化式で変数「i」は1だけ増加し、変数「j」は1だけ減少させています。このように一つのfor文で複数の変数の初期化と変化をさせることができます。 なお変数の宣言を伴う場合は注意して下さい。次のような記述はコンパイルエラーとなります。 for (int i = 1, int j = 9; i < 10; i++, j--){ System.out.println("i = " + i + ",j = " + j); }同じデータ型の場合であれば「int i = 1, j = 9」と記述することはできます。ただ「int i = 1, int j = 9」と記述することはできませんし、異なるデータ型の変数に対して「int i = 1, double d = 1.0」のように記述することはできません。複数の初期化式を用いる場合はfor文の外で変数宣言を行った上で初期化だけを記述します。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample4_1{ public static void main(String args[]){ int i, j; for (i = 1, j = 5; i < 6; i++, j--){ System.out.println(i + " + " + j + " = " + (i + j)); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample4_1 1 + 5 = 6 2 + 4 = 6 3 + 3 = 6 4 + 2 = 6 5 + 1 = 6 [xxxxxxxx@dddddddddd For]$ |
for文で実行されるブロックの中には様々な文を記述することができますので他のfor文を記述することができます。次の例を見て下さい。 for (int i = 0; i < 2; i++){ for (int j = 0; j < 2; j++){ System.out.println("i = " + i + ",j = " + j); } }この例では外側のfor文のブロック内に別のfor文を記述しています。ではこのサンプルがどのように実行されるのか確認してみます。 1)変数「i」を宣言し、0で初期化する 2)外側の条件式を評価し繰り返しを実行する 3)変数「j」を宣言し、0で初期化する 4)内側の条件式を評価し繰り返しを実行する 5)「i = 0,j = 0」を出力 6)変化式によって変数「j」の値を1にする 7)内側の条件式を評価し繰り返しを実行する 8)「i = 0,j = 1」を出力 9)変化式によって変数「j」の値を2にする 10)内側の条件式を評価し内側のfor文を終了する 11)変化式によって変数「i」の値を1にする 12)外側の条件式を評価し繰り返しを実行する 13)変数「j」を宣言し、0で初期化する 14)内側の条件式を評価し繰り返しを実行する 15)「i = 1,j = 0」を出力 16)変化式によって変数「j」の値を1にする 17)内側の条件式を評価し繰り返しを実行する 18)「i = 1,j = 1」を出力 19)変化式によって変数「j」の値を2にする 20)内側の条件式を評価し内側のfor文を終了する 21)変化式によって変数「i」の値を2にする 22)外側の条件式を評価し外側のfor文を終了する長くなっていますが、2)から11)までが外側のfor文の1回目の繰り返し処理、12)から21)までが外側のfor文の2回目の繰り返し処理となります。そして外側のfor文が1回回るたびに内側のfor文が繰り返し実行されることになります。 2つの変数の値をそれぞれ範囲内で変化させ、総当りの組み合わせで処理を行いたい場合に使われます。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample5_1{ public static void main(String args[]){ for (int i = 1; i <= 9; i++){ for (int j = 1; j <= 9; j++){ System.out.println(i + " × " + j + " = " + (i * j)); } } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample5_1 1 × 1 = 1 1 × 2 = 2 1 × 3 = 3 1 × 4 = 4 1 × 5 = 5 1 × 6 = 6 1 × 7 = 7 1 × 8 = 8 1 × 9 = 9 2 × 1 = 2 2 × 2 = 4 2 × 3 = 6 2 × 4 = 8 2 × 5 = 10 2 × 6 = 12 2 × 7 = 14 2 × 8 = 16 2 × 9 = 18 3 × 1 = 3 3 × 2 = 6 -- 省略 -- 8 × 5 = 40 8 × 6 = 48 8 × 7 = 56 8 × 8 = 64 8 × 9 = 72 9 × 1 = 9 9 × 2 = 18 9 × 3 = 27 9 × 4 = 36 9 × 5 = 45 9 × 6 = 54 9 × 7 = 63 9 × 8 = 72 9 × 9 = 81 [xxxxxxxx@dddddddddd For]$数が多いので全部は表示されていませんが九九を順に表示させています。 |
主に指定した回数だけ繰り返し目的で利用されるfor文に対して、条件が満たされている間は何度でも繰り返す目的で利用されるのがwhile文です。書式は次の通りです。 while (条件式){ 実行する文1; 実行する文2; ... }while文では条件式を評価しtrueだった場合には「{」から「}」のブロック内に記述された文を実行します。条件式は関係演算子及び論理演算子などを使って記述します。そしてブロック内の処理が一通り終わると改めて条件式を評価します。そしてまたtrueだった場合にはブロック内の文の実行し、falseだった場合にはwhile文を終了します。 繰り返しで実行される文が一つだった場合には「{」と「}」を省略して次のように記述することもできます。 while (条件式) 実行する文;このようにwhile文はfor文と同じように使用することができます。for文とは異なり初期化式や変化式がありませんので条件式で変数を使用する場合はwhile文よりも前で記述する必要がありますし条件式を変更するにはブロック内で自分で記述する必要があります。 ではwhile文はどのような場合に使用するのかと言えば繰り返し回数が決まっておらず、条件式で評価する値が不規則に変わるようなものです。簡単な例で言えばユーザーからパスワードなどを入力してもらい一致するまで繰り返し入力を行うような場合やテキスト文書などを読み込み、含まれていた文書を1行ずつ処理するような場合などです。ただ、for文と同じような目的でwhile文を使用しても構いません。回数が決まっている時にはfor文で回数が未定の場合はwhile文というのはあくまで目安です。 では簡単な例を使いwhile文がどのように処理されるのかを確認してみます。 int i = 0; while (i < 2){ System.out.println("i = " + i); i++; }この場合は次のような処理の流れとなります。 1)i = 0; 2)条件式を評価。iは2よりも小さいので繰り返しを実行 3)「i = 0」を画面に出力 4)i++; 5)条件式を評価。iは2よりも小さいので繰り返しを実行 6)「i = 1」を画面に出力 7)i++; 8)条件式を評価。iは2よりも小さくないので繰り返しを終了for文と同じくwhile文ではまず最初に条件式が評価されます。もしも条件式がいきなりfalseとなった場合には繰り返し処理は実行されません。条件式がtrueだった場合にはwhile文の「{」から「}」までのブロック内の文を順に実行していきます。 ブロック内の最後の文を実行したら1回目の繰り返しが終了です。そしてwhile文の最初に戻り改めて条件式を評価します。trueなら再度ブロック内の文を実行し、falseだった場合にはwhile文の次の文へ処理が移ります。 基本的にfor文と同じですが条件式を変化させるのはブロック内で記述する必要があることを忘れないようにして下さい。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample6_1{ public static void main(String args[]){ int i = 0; while (i < 2){ System.out.println("i = " + i); i++; } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample6_1 i = 0 i = 1 [xxxxxxxx@dddddddddd For]$ |
for文やwhile文ではまず条件式を評価してから1回目の繰り返しを行います。その為、場合によっては一度も繰り返し処理を行わないことがあります。それに対してまず繰り返しを一度行ってから条件式を評価したい場合に利用されるのがdo..while文です。書式は次の通りです。 do{ 実行する文1; 実行する文2; ... } while (条件式);do..while文ではまず「{」から「}」のブロック内に記述された文を実行します。そして条件式を評価しtrueだった場合には再度ブロック内の処理を行いますがfalseだった場合にはdo..while文を終了して次の文へ処理が移ります。 注意すべき点は最後にセミコロン(;)を付ける必要がある点です。これはfor文やwhile文と異なるため注意して下さい。 繰り返しで実行される文が一つだった場合には「{」と「}」を省略して次のように記述することもできます。 do 実行する文; while (条件式);ただ分かりにくくなるので省略はしないほうがいいかもしれません。 while文とdo..while文は必ず1回はブロック内の処理を実行するかどうかだけの違いです。次の例を見てください。 int i = 7; do{ System.out.println("i = " + i); i -= 4; }while(i < 0);この場合は次のような処理の流れとなります。 1)i = 7; 2)「i = 7」を画面に出力 3)i -= 4; 4)条件式を評価。iは0よりも大きいので繰り返しを実行 5)「i = 3」を画面に出力 6)i -= 4; 7)条件式を評価。iは0より大きくないので繰り返しを終了今回は対象となる数値をまず表示し、そこから順に4を減算していき0よりも小さくなったら終了するというものです。もしもwhile文で次のように記述してしまうと間違いです。 int i = 7; while(i < 0){ System.out.println("i = " + i); i -= 4; }これは対象が正の数だけの場合であれば同じ結果となりますが、負の値を対象にした場合は対象となった値が一度も表示されることなく終了してしまいます。よってwhile文で同じ動作をさせるには次のように記述しなければなりません。 int i = 7; System.out.println("i = " + i); while(i < 0){ i -= 4; System.out.println("i = " + i); }do..while文で記述できることは基本的にwhile文でも記述することができますが、do..while文を使った方が簡潔に記述できる場合があります。そのような時にdo..while文を使って下さい。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample7_1{ public static void main(String args[]){ int i = 7; do{ System.out.println("i = " + i); i -= 4; }while(i > 0); System.out.println("0を下回ったので終了です"); i = -3; do{ System.out.println("i = " + i); i -= 4; }while(i > 0); System.out.println("0を下回ったので終了です"); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample7_1 i = 7 i = 3 0を下回ったので終了です i = -3 0を下回ったので終了です [xxxxxxxx@dddddddddd For]$ |
for文の少し違った使い方として拡張for文(for-each文)という使い方ができるようになりました。これは配列やコレクションと呼ばれる複数の要素を持っているものから全ての要素に含まれる値を順に取り出して処理するために使われます。配列やコレクションについては今後別のページで詳しく解説しますのでこの時点ではそういった文が用意されていることだけ覚えておいて下さい。 書式は次の通りです。 for (データ型 変数名: コレクション){ 実行する文1; 実行する文2; ... }以前に解説したfor文と同じですが括弧の中はまったく別のものとなっています。この形式では値を順に取り出したい配列やコレクションと、取り出した値を格納する変数の二つをセミコロン(;)ではなくコロン(:)で区切って記述します。繰り返される回数は配列やコレクションに含まれている値の数だけなので条件式は必要ありませんし変化式も必要ありません。 実際には次のような使い方となります。 int data[] = {85, 72, 89}; for (int seiseki: data){ System.out.println(seiseki); }この場合は次のような処理の流れとなります。 1)配列dataを宣言し初期化 2)配列から要素に含まれる値を1つ取り出し変数seisekiに代入 3)変数seisekiを出力 4)配列から要素に含まれる値を1つ取り出し変数seisekiに代入 5)変数seisekiを出力 6)配列から要素に含まれる値を1つ取り出し変数seisekiに代入 7)変数seisekiを出力 8)配列から全ての値を取り出したので繰り返しを終了今回は配列の3つの要素がありますので、3つの要素に含まれる値を取り出しながらブロック内の処理を行っていきます。 なおfor-each文は比較的新しく用意された文で、以前であれば次のように記述していました。 int data[] = {85, 72, 89}; for (int i = 0; i < data.length; i++){ System.out.println(data[i]); }全ての要素の合計を取得したい場合など取り出す順序に関係なく全ての要素を1回ずつ取り出したい場合に便利な文です。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample8_1{ public static void main(String args[]){ int data[] = {85, 72, 89, 54, 91}; for (int seiseki: data){ System.out.println(seiseki); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd For]$ java JSample8_1 85 72 89 54 91 [xxxxxxxx@dddddddddd For]$ |
|