【Java】ループ処理
for 文
String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
for (int i = 0; i < fruits.length; i++) {
System.out.println(fruits[i]);
}
おそらく最初に覚えるであろう、基本的なループ処理です。
for 文は、主に以下の用途で使用されます。
- 決まった回数のループ処理
- インデックスが必要な配列、コレクションのループ処理
- ループ毎に一定の変化を行うループ処理
for 文には、初期化式、条件式、変化式の 3 つの要素を順に設定します。
初期化式
初期化式では、ループで使用する変数のループ開始時の値を設定します。
変数は事前に用意してもよいのですが、上例のint i = 0
のように初期値として変数を定義することができます。
この場合、変数のスコープは for 文の処理内となります。
そのため for 文の処理ないでしか使用しない場合はこちらを使用します。
//変数自体を定義したfor文
for (int i = 0; i < fruits.length; i++) {
//変数 i はこの中でのみ使用可能
}
//事前に変数を用意したfor文
int j = 0;
for (j = 0; j < fruits.length; j++) {
//変数 j はこの中で使用可能
}
//変数 j はfor文の外でも使用可能
//for文によって値が変化していることに注意
条件式
条件式には、ループ処理を継続するための条件を設定します。条件式を満たさなくなった場合にループが終了します。
条件式を設定しなかった場合は、永久ループになります。
for (int i = 0; ; i++) {
//永久ループ
}
変化式
変化式には、ループが終わるたびにどのような処理を行うかを設定します。
上例では、変数i
をインクリメントしています。
複数変数
使用する頻度は少ないかもしれませんが、以下のようにカンマで区切ることで複数の変数を使用できます。
for (int i = 0; j = 1; i < fruits.length; i++, j += 2) {
//...
}
while 文、do-while 文
//while文
String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
int i = 0;
while (i < fruits.length) {
System.out.println(fruits[i]);
i++;
}
//do-while文
int j = 0;
do {
System.out.println(fruits[j]);
j++;
} while (j < fruits.length);
while 文、do-while 文は条件式のみを設定します。条件式の考え方は for 文と同じです。
for 文と同じく終了条件を設定しなかった場合は永久ループとなります。
while () {
//...
}
do {
//...
} while();
while 文と do-while 文の違いは終了条件の判定のタイミングです。
while 文はループ処理の開始前に行い、do-while 文はループ処理の終了後に行います。 つまり、do-while 文は終了条件を満たしていたとしても必ず 1 度はループ処理が実行されます。
int i = 3;
while (i < 3) {
//これは実行されない
}
do {
//これは1回実行される
} while (i < 3)
do-while 文はコーディング規約によって使用を禁止されているケースもしばしば見かけます。
拡張 for 文
String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
for (String fruit : fruits) {
System.out.println(fruit);
}
拡張 for 文では、配列またはコレクション(List
など)の要素を順に指定した変数に格納します。
ループ処理は、要素数分行われます。
インデックスが不要な配列、コレクションのループ処理の場合は、for 文ではなく拡張 for 文を利用するほうがよいでしょう。
上例ではfruits
の要素が順にfruit
に格納されます。
forEach (Stream API)
String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
Arrays.stream(fruits)
.forEach(fruit -> {
System.out.println(fruit);
});
Java8 から使用できる方法です。
考え方は拡張 for 文と同じで、配列やコレクションの要素を順に変数に格納します。
ただし、配列はそのままでは使用できないためstream
に変換してからループ処理を行います。
ループ処理はラムダ式で定義します。ラムダ式についてはこの記事では割愛します。
forEach はデメリットも多く、仕様をよく理解せずに利用すると大変苦労します。無理に使用せず、拡張 for 文を使用することをオススメします。
ループ制御
これから説明することはforEachでは使用できません。
continue
for (String fruit : fruits) {
if ("オレンジ".equals(fruit)) {
continue;
}
System.out.println(fruit);
}
//リンゴ、バナナが出力
continue
を指定すると、continue
の後に定義された処理は実行されず、次のループ処理が行われます。
break
for (String fruit : fruits) {
if ("オレンジ".equals(fruit)) {
break;
}
System.out.println(fruit);
}
//リンゴのみ出力
break
は、ループを強制的に終了させたい場合に使用します。
上例では、要素の値がオレンジの場合にループを終了させているため、リンゴのみ出力されます。
ラベル付きループ
ループ処理にはラベルを付与することができます。
これまでの例とは異なりますが、以下のような多重ループの際にcontinue
やbreak
と組み合わせて使用します。
loop: for (int i = 0; i < 3; i++) {
System.out.println("Start: " + i);
for (int j = 0; j < 3; j++) {
if (i * j == 1) {
continue loop;
}
System.out.println(String.format("%d, %d", i, j ));
}
System.out.println("End: " + i);
}
//【出力結果】
//Start: 0
//0, 0
//0, 1
//0, 2
//End: 1
//Start: 1
//1, 0
//Start: 2
//2, 0
//2, 1
//2, 2
//End: 2
continue
と組み合わせる場合、continue ラベル名
とすることでラベルのついたループに対し、次のループ処理を実行するようにします。
loop: for (int i = 0; i < 3; i++) {
System.out.println("Start: " + i);
for (int j = 0; j < 3; j++) {
if (i * j == 1) {
break loop;
}
System.out.println(String.format("%d, %d", i, j ));
}
System.out.println("End: " + i);
}
//【出力結果】
//Start: 0
//0, 0
//0, 1
//0, 2
//End: 1
//Start: 1
//1, 0
break
と組み合わせる場合、break ラベル名
とすることでラベルのついたループ処理を終了させます。
ラベルは while 文や拡張 for 文でも使用できます。