こんにちは。ECF Techブログ
担当 Michiharu.Tです。
Javaプログラミング入門記事の第4章をお送りいたします。
第4章のテーマは「制御構文」です。今回は2部構成のうちのPart2となります。
本連載の初回および章立ての一覧については下記のリンクから確認できます。
解説動画
2023/12/16 解説動画を掲載しました。
4-5 while文
本節から、反復、いわゆるくり返し文の説明を行います。始めにwhile文です。while文はシンプルなくり返し処理を実現します。
文法を示します。
while(条件式){ //条件式がtrueの間くり返す処理 }
- 条件式が
true
の間、ブロック内の処理をくり返します。
プログラム例を示します。
プログラム例
public class Main{ public static void main(String[] args){ int i = 0; while(i < 3) { System.out.println("i = " + i); i++; } } }
実行結果
i = 0 i = 1 i = 2
解説
- 変数iはくり返し回数を数えるための変数です。このような目的の変数をカウンタとも言います。
- while文は次の2つをくり返します。
- 条件式が
true
ならブロック内の処理を行なう。false
ならwhile文を終了し、その次行へジャンプ。 - ブロック内の処理が終わったら、ブロックの先頭に戻る。
- 条件式が
- while文内でiが1加算(
i++
)されることにより、くり返しが3回で終わるようになっています。 - while文のくり返しの様子を下図に示します。
※吹き出しは処理時の変数iの値です。
4-5-1 無限ループ
4-5で示したプログラムにおいて、i++;
は重要な役割を担っています。この文が無い下のようなプログラムは、while文の条件式i < 3
がいつまでたってもfalse
にならないため、無限ループという状態に陥ります。
プログラム例
public class Main{ public static void main(String[] args){ int i = 0; while(i < 3) { System.out.println("i = " + i); } } }
実行結果
i = 0 i = 0 i = 0 i = 0 : (無限にi=0が表示され続ける) :
プログラムがこのような無限ループ状態に陥ったら、Ctrlキー + c
を押すことでプログラムを強制終了できます。
4-6 do-while文
do-while文はwhile文とよく似たくり返し文です。違いは条件判定を最初に行うか最後に行うかの違いです。
do-while文では条件判定を最後に行うため、ブロック内の処理が最低1回は実行されます。文法を示します。
do{ //条件式がtrueの間くり返す処理 } while(条件式);
条件式や処理がほぼ同一の2つのプログラムを比較し、動作の違いを確認します。
プログラム例(while文の場合)
public class Main{ public static void main(String[] args){ int i = 3; while(i < 3) { System.out.println("i = " + i); i++; } } }
実行結果
何も表示されません
プログラム例(do-while文の場合)
public class Main{ public static void main(String[] args){ int i = 3; do { System.out.println("i = " + i); i++; } while(i < 3); } }
実行結果
i = 3
解説
どちらのプログラムも変数iの初期値は3
となっており、条件式i < 3
は初回の判定でfalse
となりますが、do-while文ではブロック内の処理が1回実行されています。
4-7 for文
for文はくり返し文の1つで、くり返しに必要な処理を定義部分にまとめて記述できるという特徴があります。文法を示します。
for(初期処理;条件式;後処理){ //条件式がtrueの間くり返す処理 }
for文の定義部分は、;
で区切られた3つのパートに分かれています。
- 初期処理:カウンタに使う変数などを宣言します。
- 条件式:くり返し文を継続する条件式を記述します。
- 後処理:カウンタの1加算などを行います。
for文の動作順序をフローチャートに示すと次のようになります。
- 初期処理は最初の1回だけ実行されます。
- あとは条件式が
true
の間、ブロック内処理と後処理をくり返します。
プログラム例を示します。
プログラム例
public class Main { public static void main(String[] args) { for(int i = 0; i < 3; i++) { System.out.println("i = " + i); } } }
実行結果
i = 0 i = 1 i = 2
解説
- 始めに
int i = 0;
を実行します。変数iを宣言しています。 - 以降は下を繰り返します。
i < 3
を判定する。true
なら2.へ。false
ならforループ終了。System.out.println("i = " + i);
を実行。i++
を実行し、1.に戻る
for文の部分の動作イメージを下図に示します。
※矢印は処理の順番、吹き出しは処理時の変数iの値です。
4-8 制御構文の入れ子
ある制御構文のブロック内に別の制御構文が記述された状態を入れ子(ネスト) と言います。制御構文を入れ子にすることで複雑な処理が実現できます。
プログラム例を示します。
プログラム例
public class Main { public static void main(String[] args) { for( int i = 1; i <= 5; i++ ) { if( i % 2 == 0 ) { //iが偶数なら System.out.println(i + "は偶数です"); } else { System.out.println(i + "は奇数です"); } } } }
実行結果
1は奇数です 2は偶数です 3は奇数です 4は偶数です 5は奇数です
解説
for文の中にif文が入った入れ子構造になっています。入れ子になったプログラムを読み解く際は、各ブロックが何をしているかを大まかにつかむと良いでしょう。今回のプログラムだと次のようなイメージです。
if文の条件式i % 2 == 0
は、iを2で割った余りが0
か1
かで偶数か奇数かを判定しています。余りが0
なら偶数となります。
4-8-1 二重ループ
入れ子の中でも複数のくり返し文を入れ子にしたプログラムは、処理量が増大するためイメージが難しいプログラムの1つです。ここでは、二重ループのプログラムを例としてご紹介します。
プログラム例
public class Main { public static void main(String[] args) { for(int i = 1; i <= 3; i++) { for(int j = 1; j <= 3; j++) { System.out.print(i*j + " "); } //改行のみ System.out.println(); } } }
実行結果
1 2 3 2 4 6 3 6 9
解説
- 2つのfor文が入れ子になっています。
- 外側のfor文は3回のくり返しを行います。
- 内側のfor文は、外側のfor文1回につき、3回のくり返しを行います。
プログラムの動作イメージを下図に示します。
- 左側から順に外側のforループの1回目、2回目、3回目となっています。
- 吹き出しはそれぞれのタイミングでの変数iとjの値です。
4-9 continue文とbreak文
- continue文を使うと、くり返し処理を1回スキップすることができます。
- break文を使うと、くり返し文を途中で抜けることができます。
書き方はそれぞれ、下のように記述するだけです。
continue; //continue文の実行
break; //break文の実行
プログラム例を示します。
プログラム例
public class Main { public static void main(String[] args) { //iを0~9まで1ずつ増加しながらくり返す for(int i = 0; i < 10; i++) { //iが3ならfor文の先頭へ戻る if( i == 3 ) { continue; } //iの値を表示 System.out.println("i = " + i); //iが5ならfor文をぬける if( i == 5 ) { break; } } } }
実行結果
i = 0 i = 1 i = 2 i = 4 i = 5
解説
- 変数iが
3
の時は、条件式i == 3
がtrue
となるため、continue;
が実行されます。 - continue文が実行されると、以降のブロック内処理を行わずにfor文の先頭に戻ります。そのため
i = 3
は表示されません。この時i++
が実行されていることに注意が必要です。 - 変数iが
5
の時は、条件式i == 5
がtrue
となるため、break;
が実行されます。 - break文が実行されるとくり返し文を抜けます。よってfor文が終了となり、同時にプログラムが終了します。
下はプログラムの動作イメージです。
4-10 ブロックとスコープ
制御構文を学んだことで、登場したブロックがかなり増えてきました。下記はここまで学習したブロックの一覧になります。
- クラス
- メソッド
- if
- else if
- else
- switch
- while
- do-while
- for
ブロックの記述が増えてきた際に注意しておきたいのが、次に示すスコープです。
4-10-1 スコープ
スコープ(scope) は簡単に言えば「利用可能な範囲」です。ここではプログラム例を使って、変数のスコープについて説明します。
プログラム例
public class Main { public static void main(String[] args){ int num = 5; if( num != 0 ){ int ans = num * 4; System.out.println("答えは" + ans ); } System.out.println("答えは" + ans ); } }
コンパイル結果
Main.java:8: エラー: シンボルを見つけられません System.out.println("答えは" + ans ); ^ シンボル: 変数 ans 場所: クラス Main エラー1個
解説
コンパイルを行なった結果、エラーとなっています。エラーメッセージはans
という変数が宣言されていないことを示しています。5行目において、int ans = num * 4;
の形で変数ansを宣言しているにも関わらず、どうしてこのようなエラーが発生するのでしょうか?
理由は、ブロック内で宣言した変数はブロック内でしか使用できない。 というルールがあるからです。
5行目の変数ans
は、if文のブロック内で宣言されています。この時、変数ansが利用可能な範囲はifブロック内の宣言行より下部分のみとなります(下図)。したがって7行目時点では変数ans
が存在せず、エラーとなってしまいます。
一方でブロックが異なれば、同じ名前の変数が宣言できます。プログラム例を示します。
プログラム例
public class Main { public static void main(String[] args){ for(int i = 0; i < 3; i++){ System.out.println(i); } for(int i = 0; i < 3; i++){ System.out.println(i); } } }
実行結果
0 1 2 0 1 2
解説
変数iの値を3回表示するfor文が2つ並んでいるプログラムです。この2つのfor文にあるint i = 0;
は変数宣言です。どちらも同じ変数名i
を宣言していますが、エラーにはなりません。これは、お互いが別々のfor文のブロックで宣言されているためです(定義部分もブロック内とみなされます)。