広告

Java : while文の基本 (文法)

while文は、プログラムを繰り返し処理するための、もっとも原始的な方法です。
より優れた方法もいろいろあります。特に 拡張for文 (for-eachループ文) はおすすめです。

とはいえ、while文が必要となるケースもあります。
本記事では、そんな while文の基本的な使い方をご紹介します。


while文

while文 (英: while statement) はプログラミング言語において繰り返し(ループ)の制御構造を記述するための文 (statement) である。

while文は、プログラムを繰り返し処理させるための制御文です。

while (条件式) {
    ... ループ文 ...
}

これが基本の形となります。
条件式が true の間はループ文を繰り返し実行します。

コード例を見てみましょう。
※System.out.println は、値をコンソールに出力するためのメソッドです。

var num = 0;
while (num < 3) {
    num++;
    System.out.println("num = " + num);
}

// 結果
// ↓
//num = 1
//num = 2
//num = 3

条件式は

num < 3

の部分です。
条件式をチェックするときに num < 3 であれば、ループ文を実行します。

ループ文は

num++;
System.out.println("num = " + num);

の部分です。
num 変数を 1加算して、num 変数の値をコンソールに出力させています。

処理の流れは次のようになります。

  1. num 変数を 0 で初期化。
  2. while文開始
    1. 条件式をチェック。num = 0 なので 0 < 3 ... 結果は true、ループ文を実行します。
    2. ループ文を実行。num変数 に 1を加算してコンソールに出力します。

    3. 条件式をチェック。num = 1 なので 1 < 3 ... 結果は true、ループ文を実行します。
    4. ループ文を実行。num変数 に 1を加算してコンソールに出力します。

    5. 条件式をチェック。num = 2 なので 2 < 3 ... 結果は true、ループ文を実行します。
    6. ループ文を実行。num変数 に 1を加算してコンソールに出力します。

    7. 条件式をチェック。num = 3 なので 3 < 3 ... 結果は false、while文を終了します。
  3. while文終了

結果として、コンソールには

num = 1
num = 2
num = 3

と出力されます。

注意する点としては、num 変数が 3 になった瞬間に while文が終わるわけではない、ということです。
あくまで条件式がチェックされるタイミングで num < 3 であれば while文は終了します。

フローチャート図で書くと次のようになります。

フローチャート図(while文)

それでは、もう少し詳しく見ていきましょう。


条件式

while (条件式) {
    ... ループ文 ...
}

条件式は、結果が boolean(真偽値) となる のみ許容します。
boolean にならないものはコンパイルエラーとなります。

例えば <> による大小の比較や、== による比較は、結果が boolean となる式です。

// 式 : 5 > 3
final var exp1 = 5 > 3;
System.out.println(exp1); // true

// 式 : 4 < -1
final var exp2 = 4 < -1;
System.out.println(exp2); // false

// 式 : 10 == 10
final var exp3 = 10 == 10;
System.out.println(exp3); // true
// コンパイルOK
var num = 5;

while (num > 3) {
    ...
}

while (num < -1) {
    ...
}

while (num == 10) {
    ...
}

もしくは、結果が boolean となるメソッドの呼び出しも OK です。
例えば、文字列の比較に使う equals メソッドは boolean を返します。

final var exp1 = "abc".equals("abc");
System.out.println(exp1); // true

final var exp2 = "abc".equals("xyz");
System.out.println(exp2); // false
// コンパイルOK
var str = "abc";

while (str.equals("xyz")) {
    ...
}

複数の条件式を使いたい場合は &&|| といった論理演算も使えます。

final var exp1 = 5 > 3;
System.out.println(exp1); // true

final var exp2 = "abc".equals("xyz");
System.out.println(exp2); // false

final var exp3 = exp1 && exp2;
System.out.println(exp3); // false

final var exp4 = exp1 || exp2;
System.out.println(exp4); // true
// コンパイルOK
var num = 5;
var str = "abc";

while (num > 3 && str.equals("xyz")) {
    ...
}

while (num > 3 || str.equals("xyz")) {
    ...
}

足し算、引き算など +- を使った式は、結果が数値となります。
boolean ではないので while文の条件式には使えません。

// 式 : 5 + 3
final var exp1 = 5 + 3;
System.out.println(exp1); // 8

// 式 : 4 - 1
final var exp2 = 4 - 1;
System.out.println(exp2); // 3
// コンパイルエラー
var num = 5;

while (num + 3) {
    ...
}

while (num - 1) {
    ...
}

補足

  • Java以外のプログラミング言語には、条件式に boolean 以外を許容しているものもあります。
    例えば C言語では、条件式に数値も許容しています。 0 は false、それ以外は true として扱います。
  • しかし、Java では厳密に boolean のみを許容します。0 や 1 といった数値を条件式に使うとコンパイルエラーになります。

break文

while (条件式) {
    ... ループ文 ...

    if (...) {
        break;
    }
}

さて、今までのコード例では、while文を終わらせるには条件式を false にする必要がありました。

しかし、条件式以外の任意の箇所で while文から抜けたい (終わらせたい) ことがあるかもしれません。
そんなときに使えるのが break文です。

break文は、ループ文の中で次のように書きます。

break;

コード例で見てみましょう。

var num = 0;
while (true) {
    System.out.println("------");
    System.out.println("loop : start");

    num++;
    System.out.println("  num = " + num);

    if (num == 3) {
        System.out.println("Break!");
        break;
    }

    System.out.println("loop : end");
}

// 結果
// ↓
//------
//loop : start
//  num = 1
//loop : end
//------
//loop : start
//  num = 2
//loop : end
//------
//loop : start
//  num = 3
//Break!

今回は、while文を break文で終わらせたいので、条件式には true を直接指定しています。
これで、条件式では while文は終わらなくなりました。

while (true) {
    ...
}

ループ文では num 変数を 1 ずつ加算します。
そして、num が 3 になったときに "Break!" と出力して break文 で while文を抜けます。

System.out.println("------");
System.out.println("loop : start");

num++;
System.out.println("  num = " + num);

if (num == 3) {
    System.out.println("Break!");
    break;
}

System.out.println("loop : end");

結果は次のように出力されます。

------
loop : start
  num = 1
loop : end
------
loop : start
  num = 2
loop : end
------
loop : start
  num = 3
Break!

ここで注目したいのが、num = 3 のときのループ処理では、最後の "loop : end" が出力されない ことです。
break文で while文を抜けると、break以降の処理は実行されません。

continue文

while (条件式) {
    ... ループ文 ...

    if (...) {
        continue;
    }
}

continue文を使うと、ループ文の処理をそこでやめて while文の開始処理へジャンプする、という制御ができます。

continue文は、ループ文の中で次のように書きます。

continue;

文章では少しわかりにくいかもしれません。
コード例で見てみましょう。

var num = 0;
while (num < 4) {
    System.out.println("------");
    System.out.println("loop : start");

    num++;
    System.out.println("  num = " + num);

    if (num % 2 == 0) {
        System.out.println("Continue!");
        continue;
    }

    System.out.println("loop : end");
}

// 結果
// ↓
//------
//loop : start
//  num = 1
//loop : end
//------
//loop : start
//  num = 2
//Continue!
//------
//loop : start
//  num = 3
//loop : end
//------
//loop : start
//  num = 4
//Continue!

条件式は num < 4 です。

while (num < 4) {
    ...
}

ループ文では num 変数を 1 ずつ加算します。
そして、num が偶数のとき (num % 2 == 0) は "Continue!" と出力して continue文 を実行します。

System.out.println("------");
System.out.println("loop : start");

num++;
System.out.println("  num = " + num);

if (num % 2 == 0) {
    System.out.println("Continue!");
    continue;
}

System.out.println("loop : end");

結果は次のように出力されます。

------
loop : start
  num = 1
loop : end
------
loop : start
  num = 2
Continue!
------
loop : start
  num = 3
loop : end
------
loop : start
  num = 4
Continue!

num が奇数のときは continue文は実行されません。
そのため、ループ処理の最初で "loop : start" と出力され、ループ処理の最後で "loop : end" と出力されます。

num が偶数のときは continue文が実行されます。
continue文が実行されると、すぐに while文の開始処理へジャンプします。"loop : end" は出力されません


無限ループに注意

無限ループ(むげんループ)は、コンピュータ・プログラム等の一連の手続き等が無限に繰り返される(ループする)ことである。永久ループ(えいきゅうループ)ともいう。

while文を使うときは、無限ループに注意しましょう。

もし無限ループが起きてしまうと、不具合の症状の1例としては、アプリは反応がなくなりフリーズしてしまいます。
アプリのクラッシュと並んで、致命的なバグの1つですね。

次のコード例を見てみましょう。

double num = 1.0;
while (num > 0.0) {
    num *= 10;
    System.out.println(num);
}

num は浮動小数点数(double)です。

num が 0 より大きい間、ループを続けます。
そして、ループ文では num を 10倍していきます。

出力は次のようになります。

10.0
100.0
1000.0
10000.0
100000.0
1000000.0
... 省略 ...
9.999999999999999E306
9.999999999999998E307
Infinity
Infinity
Infinity
... 省略 ...

num の値が、10 → 100 → 1000 → 10000 ... と増えているのがわかりますね。
さらに続けていくと、最終的には正の無限大(Infinity) となります。

Infinity は、そこからいくら 10倍しても Infinity のままです。
そして Infinity は 0 より大きいので、この while文は永遠に実行し続けることになります。

これが無限ループです。

while文を使うときは、条件式や break文で、きちんとループが終了するかを常に気にかけなければなりません。
これがなかなか神経を使うのですよね…

もし 拡張for文 (for-eachループ文) が使えるケースであれば、そちらを使うことをおすすめします。
拡張for文は、なんと条件式を使わずにループ処理が可能です。(その代わり使えるケースは限定的です)

{ } の省略

while (条件式)
    ループ文

ループ文が 1つの文 のみの場合は { } を省略することができます。

var num = 0;

// 通常の書きかた
while (num < 3) {
    num++;
}

// こう書いたり…
while (num < 3)
    num++;

// こう書くこともできます。
while (num < 3) num++;

ただし、{ } を省略すると、思わぬコーディングミスを誘発してしまうかもしれません。

次のコード例を見てみましょう。

var num = 0;
while (num < 3) System.out.println(num); num++;

さて、ぱっと見て、どのような結果になるかわかりますでしょうか。

実は、この while文は無限ループします。
コンソールには

num = 0
num = 0
num = 0
num = 0
num = 0
...

と、"num = 0" が出力され続けます。

なぜこのような結果になるのか考えてみましょう。

while文の { } を省略したので、ループ文は

System.out.println(num);

1つの文 だけが対象となります。
その後ろの

num++;

の文は、while文の外側となります。
つまり次のコードと同じ意味になります。

var num = 0;
while (num < 3) {
    System.out.println("num = " + num);
}
num++;

num 変数は while文で変わることはないので、いつまでも条件式は false にならず無限ループしてしまう…というわけでした。

{ } がないと、どこまでが ループ文なのか分かりにくくなることがあります。
個人的には、1つの文のみの場合でも { } は省略しないほうがよいんじゃないかな…と思います。


do-while文

while文と似た制御文に、do-while文があります。

do {
    ... ループ文 ...
} while (条件式);

do-while文は、条件式がループ文の後ろにきます。

var num = 0;
do {
    num++;
    System.out.println("num = " + num);
} while (num < 3);

// 結果
// ↓
//num = 1
//num = 2
//num = 3

フローチャートでは次のようになります。

フローチャート図(do-while文)

do-while文は、条件式によらずにループ文を必ず1回は実行したい、というときに便利なことがあります。

次のコードは、条件式が最初から false になる例です。
while文と do-while文の制御の違いが確認できるかと思います。

while文の例 do-while文の例
var num = 5;

System.out.println("while : start");
while (num < 3) {
    num++;
    System.out.println("  num = " + num);
}
System.out.println("while : end");

// 結果
// ↓
//while : start
//while : end
var num = 5;

System.out.println("while : start");
do {
    num++;
    System.out.println("  num = " + num);
} while (num < 3);
System.out.println("while : end");

// 結果
// ↓
//while : start
//  num = 6
//while : end

break文や continue文については、while文と同じように do-while文でも使えます。

代替えとなる方法

Java言語には、while文の代わりとなるものがいくつか用意されています。
ここではそれらを簡単にご紹介します。

基本for文

基本for文は、変数を使ってループ回数を制御するのに優れた、繰り返し制御文です。

for (初期化処理; 条件式; 更新処理) {
    ... ループ文 ...
}

これが基本の形となります。

処理の流れは次のようになります。

  1. for文開始
    1. 初期化処理を実行。

    2. 条件式を判定。true であればループ文を実行。false であれば for文は終了。
    3. ループ文を実行。
    4. 更新処理を実行。
    5. 条件式の判定に戻る。

  2. for文終了

コード例です。

for (int i = 0; i < 5; i++) {
    System.out.println("i = " + i);
}

// 結果
// ↓
//i = 0
//i = 1
//i = 2
//i = 3
//i = 4

これは while文を使って次のように記述するのと同じです。

{
    int i = 0;
    while (i < 5) {
        System.out.println("i = " + i);
        i++;
    }
}

// 結果
// ↓
//i = 0
//i = 1
//i = 2
//i = 3
//i = 4

基本for文については、よろしければ下記の記事もご参照ください。


拡張for文

for (T value : "配列""Iterable" を実装したクラス) {
    ...
}

拡張for文は、配列 もしくは Iterable を実装したオブジェクトに対して、繰り返し処理を行います。
例えば List は Iterable を実装しています。

条件式は必要とせず、すべての要素に対して繰り返し処理が実行できます。

Iterable は基本有限なので、無限ループの心配はほぼありません。 (実装次第では無限にもできますが…)

List の要素に順次アクセスして出力する例です。

final var list = List.of("aaa", "bbb", "ccc");

for (final var value : list) {
    System.out.println("value = " + value);
}

// 結果
// ↓
//value = aaa
//value = bbb
//value = ccc

これは while文を使って次のように記述するのと同じです。

final var list = List.of("aaa", "bbb", "ccc");

final var it = list.iterator();
while (it.hasNext()) {
    final var value = it.next();
    System.out.println("value = " + value);
}

// 結果
// ↓
//value = aaa
//value = bbb
//value = ccc

拡張for文については、よろしければ下記の記事もご参照ください。

Stream API

拡張for文をさらに発展させたものとして、Stream API があります。
こちらは少し難易度が高めなので、Javaに慣れてからでよいとは思います。

Stream API を使って List の要素を大文字に変換してから出力する例です。

final var list = List.of("aaa", "bbb", "ccc");

list.stream().map(String::toUpperCase).forEach(value -> {
    System.out.println("value = " + value);
});

// 結果
// ↓
//value = AAA
//value = BBB
//value = CCC

Stream API については下記の記事で詳しく解説していますので、興味がありましたらご参照ください。

公式ドキュメント

14.12. The while Statement
The while statement executes an Expression and a Statement repeatedly until the value of the Expression is false.

さらに詳しく while文について知りたい場合は、公式のJava言語仕様に記載があります。
(残念ながら公式の日本語訳はないようです)

まとめ

while文を使うと、プログラムを繰り返し処理させることができます。
ただし、場面によっては while文より優れた方法もあります。

例えば、基本for文や拡張for文です。

個人的には、while文が必要となるケースは少なく感じます。
拡張for文Stream API で済むことも多いです。

while文を理解できたら、ぜひ次は、拡張for文や Steream API も理解を深めましょう。


関連記事

ページの先頭へ