Java break と continue 文
Java において、break と continue ステートメントはループの実行を制御するための強力なパワーを提供します。これらを使用することで、for、while、および do-while ループの標準的な実行フローを変更し、特定のコンディション(条件)に基づいてイテレーション(繰り返し)をスキップしたり、ループ全体を完全に終了させたりすることが可能になります。
1. break 文
break 文は、ループを途中で終了させるために使用されます。ループ内部で break 文が実行されると、そのループの処理は即座に停止し、プログラムのコントロール(制御)はループ直後の次のコード行に移動します。
1.1 基本的な使い方
break の最も一般的なユースケースは、特定の条件が満たされたときに即座にループを脱出することです。以下のサンプルを見てみましょう。
public class BreakExample {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // i が 5 のとき、ループを即座に終了する
}
System.out.println("i = " + i);
}
System.out.println("ループが終了しました。");
}
}コードの解説:
forループを初期化し、1 から 10 までイテレーションするよう設定します。- ループ内で
if文を使い、iが 5 と等しいかどうかをチェックします。 iが 5 になった瞬間、break文がトリガーされます。break文はこのループを強制終了させます。- プログラムはループ外の次の行を実行し、「ループが終了しました。」とプリントします。
プログラムの出力:
i = 1
i = 2
i = 3
i = 4
ループが終了しました。i が 5 に達した時点でループが停止し、その後の 5 から 10 までのイテレーションがすべてスキップされている点に注目してください。
1.2 ネストされたループにおける break (ラベル付き break)
ネストされたループ(ループの中に別のループが入っている構造)を扱う場合、通常の break 文はそれを囲んでいる最も内側のループのみを終了させます。内側のループから外側のループまで一気に「突き破って」脱出したい場合は、ラベル付き (labeled) break 文を使用します。
public class NestedBreakExample {
public static void main(String[] args) {
outerLoop: // 外側のループに 'outerLoop' という名前のラベルを定義
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == 2 && j == 2) {
break outerLoop; // 'outerLoop' という名前のラベルが付いた外側のループを脱出
}
System.out.println("i = " + i + ", j = " + j);
}
}
System.out.println("ネストされたループが終了しました。");
}
}コードの解説:
- 2 層にネストされた
forループがあります。外側と内側はどちらも 1 から 3 までイテレーションします。 - 外側のループに
outerLoopというラベルを付けます。 - 内側のループで、
iが 2 かつjも 2 であるかをチェックします。 - 条件が満たされると、
break outerLoop;が実行されます。この命令は、outerLoopラベルが貼られたループを直接中断して脱出するようプログラムに伝えます。 - その結果、
i=2, j=2のときに内外両方のループが同時に終了し、プログラムは「ネストされたループが終了しました。」をプリントします。
プログラムの出力:
i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
ネストされたループが終了しました。もしこのラベルがない場合(単に break; と書いた場合)、i=2, j=2 のときには内側のループだけが終了し、外側のループは i=3 のラウンドへと継続されます。
2. continue 文
continue 文は、現在のイテレーションの残りのコードをスキップし、即座にループの次のイテレーションを開始するために使用されます。break がループ全体を終了させるのに対し、continue は「今回はここまでにして、次の回を始めよう」という意味になります。
2.1 基本的な使い方
特定の条件に基づいて、ループ内の特定の操作だけを避けたい場合に continue は非常に有用です。
public class ContinueExample {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 偶数の場合、今回の残りのコードをスキップして次のイテレーションへ
}
System.out.println("i = " + i);
}
System.out.println("ループが終了しました。");
}
}コードの解説:
- 1 から 10 までの
forループがあります。 - ループ内で、剰余演算子 (%) を使用して
iが偶数かどうかをチェックします。 iが偶数の場合、continue文がトリガーされます。continueは、後続のSystem.out.printlnコードを即座にスキップします。- ループは次のイテレーションに進みます(例:
i=2からi=3へ)。
プログラムの出力:
i = 1
i = 3
i = 5
i = 7
i = 9
ループが終了しました。すべての偶数 (2, 4, 6, 8, 10) がプリントされず、奇数のみが出力されていることがわかります。
2.2 ネストされたループにおける continue (ラベル付き continue)
break と同様に、continue もデフォルトでは最も内側のループにのみ作用します。内側のループから外側のループを強制的に次のイテレーションに進ませたい場合は、ラベル付き continue を使用します。
public class NestedContinueExample {
public static void main(String[] args) {
outerLoop: // 外側のループにラベルを定義
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == 2 && j == 2) {
continue outerLoop; // 内側の現在の操作を中断し、外側のループを次のラウンドへ進ませる
}
System.out.println("i = " + i + ", j = " + j);
}
}
System.out.println("ネストされたループが終了しました。");
}
}コードの解説:
- 外側のループに
outerLoopラベルを付けます。 - 内側のループにおいて、
i=2, j=2のときにcontinue outerLoop;をトリガーします。 - このコードは「現在の内側ループのアクションを即座に停止し、
outerLoopラベルが付いた外側ループの次のイテレーションを開始せよ」と伝えます。
プログラムの出力:
i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 3, j = 1
i = 3, j = 2
i = 3, j = 3
ネストされたループが終了しました。i=2 のとき、j=1 は正常に出力されていますが、j=2 を出力するはずのタイミングでラベル付き continue がトリガーされ、その時の内側ループの残りのステップが破棄され、外側ループが i=3 へ進んでいる点に注目してください。
3. 実践的なユースケースのデモンストレーション
3.1 無効なデータのフィルタリング (continue の活用)
ユーザー ID のリストを処理しており、正の ID のみを処理し、0 以下の異常な ID をスキップしたいシナリオを想定します。
public class ProcessUserIds {
public static void main(String[] args) {
int[] userIds = {101, -5, 205, 0, 302, -1, 400};
for (int userId : userIds) {
if (userId <= 0) {
continue; // 無効なユーザー ID をスキップして処理しない
}
System.out.println("ユーザー ID を処理中: " + userId);
// ここにユーザー処理の複雑なロジックがあると仮定...
}
System.out.println("ユーザー ID の処理が完了しました。");
}
}continue を使用することで、無効な ID (-5, 0, -1) が直接無視され、有効な正の ID のみが出力・処理されます。
3.2 ターゲット要素の検索 (break の活用)
もう一つの典型的なシナリオは、配列(アレイ)から特定のターゲットを検索し、見つかった瞬間に残りの要素をチェックする必要がなくなるケースです。
public class SearchArray {
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40, 50};
int target = 30;
boolean found = false; // ターゲットが見つかったかどうかをマーク
for (int number : numbers) {
System.out.println("数字をチェック中: " + number);
if (number == target) {
found = true;
break; // 見つかった!直ちにループを抜けてパフォーマンスを節約
}
}
if (found) {
System.out.println("配列内でターゲットが見つかりました: " + target);
} else {
System.out.println("配列内にターゲットは存在しません: " + target);
}
}
}プログラムが 30 を検出した時点で found が true になり、その後 break によってループを脱出します。そのため、コンソールには「数字をチェック中: 40」や 50 はプリントされません。