- JAVA
Javaのbreakとcontinueの使い方|ラベルで二重ループを抜ける
Javaのbreakは「ループを終える」文、continueは「今の回を飛ばして次の回へ進む」文です。二重ループをまとめて抜けたいときは、外側のループにラベルを付けて break ラベル名; と書きます。
この2つは短い文ですが、二重ループ・while・switch・ラムダ式と組み合わさると「どこまで抜けるのか」で迷いやすくなります。この記事では、break・continue・ラベル付き break・ラベル付き continue・return の5つを同じ二重ループで動かし、出力を並べて比較します。あわせて、while で continue して止まらなくなる例、switch の中の break がループを抜けない例、forEach のラムダ内に break を書いたときのコンパイルエラー文と代わりの書き方を、実行結果つきで確かめます。
確認環境:Ubuntu 24.04 / OpenJDK 21.0.10(java ファイル名.java で実行)。掲載した実行結果とエラー文はすべてこの環境の出力です。
breakとcontinueの早見表
| 書き方 | 動き | 書ける場所 |
|---|---|---|
break; |
いちばん内側のループ(または switch)を終える | for・while・do-while・switch の中 |
continue; |
いちばん内側のループの今の回を終え、次の回へ進む | for・while・do-while の中 |
break ラベル名; |
ラベルを付けた文(外側のループなど)を終える | ラベルを付けた文の中 |
continue ラベル名; |
ラベルを付けたループの次の回へ進む | ラベルを付けたループの中 |
return; |
メソッドそのものを終える(ループの後の処理も実行しない) | メソッド・ラムダ式の中 |
よくある疑問への答えも先にまとめます。
| 疑問 | 答え |
|---|---|
| 二重ループを一度に抜けるには? | 外側のループにラベルを付けて break ラベル名;。または探索部分をメソッドにして return |
| while で continue したら止まらない | カウンタの更新が continue の後ろにあると更新に届かない。更新を continue の前に書くか for 文にする |
| switch の中の break でループを抜けたい | そのままでは switch を抜けるだけ。ラベル付き break かフラグ変数を使う |
| forEach の中で break したい | ラムダ式の中には書けない(コンパイルエラー)。拡張 for 文、takeWhile、anyMatch、findFirst を使う |
| forEach の中で continue したい | ラムダ式の中の return; が continue に相当する。または filter を使う |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Javaのbreakとcontinueの使い方|ラベルで二重ループを抜ける」
breakとcontinueの基本の動き
まずは一重のループで、2つの違いを確かめます。1 から 5 まで数えるループで、3 のときにそれぞれの文を実行します。
public class BasicDemo {
public static void main(String[] args) {
System.out.print("break : ");
for (int i = 1; i <= 5; i++) {
if (i == 3) break; // ループそのものを終える
System.out.print(i + " ");
}
System.out.println("| ループの後");
System.out.print("continue : ");
for (int i = 1; i <= 5; i++) {
if (i == 3) continue; // この回だけ飛ばして次の回へ
System.out.print(i + " ");
}
System.out.println("| ループの後");
}
}
実行結果:
break : 1 2 | ループの後
continue : 1 2 4 5 | ループの後
break は 3 になった時点でループが終わるので、4 と 5 は出力されません。continue は 3 の回だけを飛ばし、4 と 5 は続けて出力されます。 どちらの場合も「ループの後」の処理は実行されます。
Java 言語仕様(Java SE 21 版、14.15 節)では、ラベルなしの break は「それを囲むいちばん内側の switch・while・do・for 文の直後へ制御を移す」と定義されています。「いちばん内側」という点が、二重ループや switch で迷いやすいところです。次の節で確かめます。
for文のcontinueは更新式を実行してから次の回へ進む
for 文で continue すると、i++ のような更新式が実行されてから条件の判定に進みます。そのため、for 文では continue を書いてもカウンタは必ず進みます。この性質は、後で扱う while との違いにつながります。
5つの書き方を同じ二重ループで比べる
ここがこの記事の中心です。i を 1〜3、j を 1〜3 で回す二重ループを用意し、j が 2 のときに5種類の文をそれぞれ実行して、出力がどう変わるかを比べます。内側のループの後、外側のループの後、呼び出し元に戻った後にも目印を出力しています。
public class FiveWays2 {
public static void main(String[] args) {
useBreak(); System.out.println(" <mainに戻った>");
useContinue(); System.out.println(" <mainに戻った>");
useLabeledBreak(); System.out.println(" <mainに戻った>");
useLabeledContinue();System.out.println(" <mainに戻った>");
useReturn(); System.out.println(" <mainに戻った>");
}
static void useBreak() {
System.out.print("break : ");
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) break;
System.out.print(i + "-" + j + " ");
}
System.out.print("[内側の後] ");
}
System.out.print("[外側の後]");
}
static void useContinue() {
System.out.print("continue : ");
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) continue;
System.out.print(i + "-" + j + " ");
}
System.out.print("[内側の後] ");
}
System.out.print("[外側の後]");
}
static void useLabeledBreak() {
System.out.print("break outer : ");
outer:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) break outer;
System.out.print(i + "-" + j + " ");
}
System.out.print("[内側の後] ");
}
System.out.print("[外側の後]");
}
static void useLabeledContinue() {
System.out.print("continue outer : ");
outer:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) continue outer;
System.out.print(i + "-" + j + " ");
}
System.out.print("[内側の後] ");
}
System.out.print("[外側の後]");
}
static void useReturn() {
System.out.print("return : ");
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) return;
System.out.print(i + "-" + j + " ");
}
System.out.print("[内側の後] ");
}
System.out.print("[外側の後]");
}
}
実行結果:
break : 1-1 [内側の後] 2-1 [内側の後] 3-1 [内側の後] [外側の後] <mainに戻った>
continue : 1-1 1-3 [内側の後] 2-1 2-3 [内側の後] 3-1 3-3 [内側の後] [外側の後] <mainに戻った>
break outer : 1-1 [外側の後] <mainに戻った>
continue outer : 1-1 2-1 3-1 [外側の後] <mainに戻った>
return : 1-1 <mainに戻った>
出力を表に整理します。
| 書き方 | 出力された組(i-j) | 内側の後の処理 | 外側の後の処理 | 動きのまとめ |
|---|---|---|---|---|
break; |
1-1、2-1、3-1 | 3回実行 | 実行 | 内側だけを終える。外側は続く |
continue; |
1-1、1-3、2-1、2-3、3-1、3-3 | 3回実行 | 実行 | j が 2 の回だけ飛ばす |
break outer; |
1-1 | 実行されない | 実行 | 外側ごと終える |
continue outer; |
1-1、2-1、3-1 | 実行されない | 実行 | 外側の次の回へ進む |
return; |
1-1 | 実行されない | 実行されない | メソッドを終える |
読み取れるポイントは次のとおりです。
- ラベルなしの break は内側のループだけを終えます。 外側のループは続くので、i が 2、3 の回も実行されます。「二重ループを抜けたつもりが抜けていない」というときは、この動きになっています。
break outer;は外側のループごと終えます。 出力は 1-1 だけで、内側の後の処理は一度も実行されません。break;とcontinue outer;は出力された組が同じ(1-1、2-1、3-1)ですが、内側の後の処理が違います。 break は内側のループの直後へ進むので「内側の後」が実行され、continue outer は外側の次の回へ直接進むので実行されません。- return はループの後の処理も実行しません。
break outer;との違いは、「外側の後」が出力されるかどうかです。
breakとreturnの違い
| 比べる点 | break | return |
|---|---|---|
| 終える範囲 | ループ(または switch、ラベルを付けた文) | メソッド全体 |
| ループの後に書いた処理 | 実行される | 実行されない |
| 値を返せるか | 返せない | 戻り値のあるメソッドでは値を返す |
| 書ける場所 | ループ・switch・ラベル付きの文の中 | メソッドやラムダ式の中ならどこでも |
ループの後に続けたい処理があるなら break、メソッドの役目がそこで終わるなら return と考えると選びやすくなります。
ラベルの書き方とルール
ラベルは、文の直前に「名前」とコロンを書くだけです。
outer:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) break outer;
}
}
| ルール | 内容 |
|---|---|
| 書く位置 | 抜けたい(または次の回へ進めたい)ループの直前 |
| 名前 | 変数名と同じ規則で付けられる。outer、search、next など役割がわかる名前にする |
break ラベル名; |
ラベルを付けた文の中でだけ使える。ループ以外のブロックにも使える |
continue ラベル名; |
ラベルがループに付いているときだけ使える |
ルールから外れると、コンパイルの時点で知らせてくれます。存在しないラベルを指定した場合と、ループではないブロックのラベルを continue に指定した場合を確かめます。
public class Err2 {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
break outer;
}
}
}
Err2.java:4: error: undefined label: outer
break outer;
^
1 error
error: compilation failed
public class Err4 {
public static void main(String[] args) {
block: {
continue block;
}
}
}
Err4.java:4: error: not a loop label: block
continue block;
^
1 error
error: compilation failed
二重ループを抜ける3つの方法
二重ループの中で目的の値を見つけたら全体を終えたい、という場面は多くあります。方法は3つあり、どれも同じ結果になります。
public class DoubleLoopExit {
public static void main(String[] args) {
int[][] table = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
// 方法1: ラベル付き break
String pos = "なし";
search:
for (int r = 0; r < table.length; r++) {
for (int c = 0; c < table[r].length; c++) {
if (table[r][c] == 8) {
pos = r + "行" + c + "列";
break search;
}
}
}
System.out.println("方法1 ラベル付き break : 8 は " + pos);
// 方法2: メソッドに切り出して return
System.out.println("方法2 メソッド + return : 5 は " + find(table, 5));
System.out.println("方法2 メソッド + return : 10 は " + find(table, 10));
// 方法3: フラグ変数を外側の条件に入れる
boolean found = false;
String pos3 = "なし";
for (int r = 0; r < table.length && !found; r++) {
for (int c = 0; c < table[r].length; c++) {
if (table[r][c] == 6) {
pos3 = r + "行" + c + "列";
found = true;
break; // 内側を抜ける。外側は !found で終わる
}
}
}
System.out.println("方法3 フラグ変数 : 6 は " + pos3);
}
static String find(int[][] table, int target) {
for (int r = 0; r < table.length; r++) {
for (int c = 0; c < table[r].length; c++) {
if (table[r][c] == target) {
return r + "行" + c + "列"; // メソッドごと終わるので二重ループも抜ける
}
}
}
return "なし";
}
}
実行結果:
方法1 ラベル付き break : 8 は 2行1列
方法2 メソッド + return : 5 は 1行1列
方法2 メソッド + return : 10 は なし
方法3 フラグ変数 : 6 は 1行2列
| 方法 | 書き方 | 向いている場面 |
|---|---|---|
| ラベル付き break | 外側にラベルを付けて break ラベル名; |
その場で抜けて、後ろの処理を続けたいとき |
| メソッド + return | 探索をメソッドに切り出して return | 「探して結果を返す」というまとまりがあるとき |
| フラグ変数 | boolean の変数を外側の条件に入れる | ラベルを使わない方針のコードに合わせるとき |
探索の結果を返すだけなら、メソッドに切り出して return する形が読みやすくなります。 メソッド名が処理の説明になり、見つからなかった場合の戻り値も1か所にまとまります。ラベル付き break は、メソッドに分けるほどではない短い処理や、ループの後に同じ変数を使って処理を続けたいときに合います。
フラグ変数の方法では、内側の break と外側の条件(!found)の両方が必要です。どちらかを書き忘れると外側のループが続くので、3つの中では書く量と確認する点が多めです。
ラベル付きcontinueとラベル付きブロック
ラベルは break だけでなく continue にも使えます。また、ループではないブロックにラベルを付けて break で抜けることもできます。
public class LabelMore {
public static void main(String[] args) {
// 1) ラベル付き continue: 0 を含む行は合計を出さずに次の行へ
int[][] rows = {{1, 2}, {3, 0}, {5, 6}};
next:
for (int[] row : rows) {
int sum = 0;
for (int v : row) {
if (v == 0) continue next;
sum += v;
}
System.out.println("合計 " + sum);
}
// 2) ラベル付きブロック: ループ以外でも「break ラベル」は使える
check: {
String name = "";
if (name.isEmpty()) {
System.out.println("名前が空なので確認を打ち切り");
break check;
}
System.out.println("ここは実行されない");
}
System.out.println("ブロックの後");
// 3) finally は break / continue で抜けるときも実行される
for (int i = 1; i <= 2; i++) {
try {
if (i == 1) continue;
break;
} finally {
System.out.println("finally (i=" + i + ")");
}
}
// 4) while (true) と break の組み合わせ
int count = 0;
while (true) {
count++;
if (count >= 3) break;
}
System.out.println("count=" + count);
}
}
実行結果:
合計 3
合計 11
名前が空なので確認を打ち切り
ブロックの後
finally (i=1)
finally (i=2)
count=3
- 1) ラベル付き continue:0 を含む行(
{3, 0})は、合計の出力を飛ばして次の行へ進んでいます。ラベルなしの continue では内側のループの次の要素へ進むだけなので、合計の出力まで飛ばしたいときにラベルが役立ちます。 - 2) ラベル付きブロック:
break ラベル名;はループ以外のブロックでも使えます。使う機会は多くありませんが、Java の文法として用意されています。 - 3) finally との関係:try の中で break や continue を実行しても、finally は実行されます。i が 1 の回(continue)でも 2 の回(break)でも finally の出力があります。後片付けの処理は finally に書いておけば、途中で抜けても実行されます。
- 4) while (true) と break:条件を true にしたループは、中の break で終わらせます。「終了条件がループの途中で決まる」処理に使う形です。
whileでcontinueすると止まらなくなる例
while 文で continue を使うときは、カウンタの更新の位置に注意が必要です。 更新が continue の後ろにあると、continue した回は更新に届かず、同じ値のまま条件の判定に戻ります。
次のコードの最初のループがその形です。本当に止まらなくなると結果を確認できないので、10 回で打ち切る安全装置(guard)を入れて動きを確かめています。
public class WhileContinue {
public static void main(String[] args) {
// 止まらなくなる書き方(確認のため 10 回で打ち切る安全装置つき)
int i = 1;
int guard = 0;
System.out.print("更新が continue の後ろ : ");
while (i <= 5) {
if (++guard > 10) { System.out.print("... 10回で打ち切り (i=" + i + ")"); break; }
if (i == 3) continue; // i++ に届かないので i は 3 のまま
System.out.print(i + " ");
i++;
}
System.out.println();
// 直し方1: continue の前に更新する
i = 0;
System.out.print("更新を先に書く : ");
while (i < 5) {
i++;
if (i == 3) continue;
System.out.print(i + " ");
}
System.out.println();
// 直し方2: for 文にする(continue しても i++ は必ず実行される)
System.out.print("for 文にする : ");
for (int k = 1; k <= 5; k++) {
if (k == 3) continue;
System.out.print(k + " ");
}
System.out.println();
// do-while の continue は条件式の判定へ進む
int n = 0;
System.out.print("do-while : ");
do {
n++;
if (n == 3) continue;
System.out.print(n + " ");
} while (n < 5);
System.out.println();
}
}
実行結果:
更新が continue の後ろ : 1 2 ... 10回で打ち切り (i=3)
更新を先に書く : 1 2 4 5
for 文にする : 1 2 4 5
do-while : 1 2 4 5
最初のループは、i が 3 になると continue で条件の判定に戻り、i++ に届かないので i は 3 のままです。安全装置がなければ、このループは終わりません。
| 直し方 | 内容 |
|---|---|
| 更新を continue の前に書く | ループの先頭で i++ してから判定する(初期値と条件も合わせて調整する) |
| for 文にする | for 文は continue しても更新式が必ず実行される |
| 飛ばす条件を if で囲む | continue を使わず、if (i != 3) { ... } で処理を囲む |
回数が決まっているループは for 文で書くと、この現象を避けられます。while 文は「条件が変わるまで続ける」処理に向いているので、continue を使うときは「次の回の条件が変わる処理を済ませたか」を確認してから書くと安心です。
do-while 文の continue は、末尾の条件式の判定へ進みます。上の例では n の更新をループの先頭に書いているので、問題なく進んでいます。
switchの中のbreakはループを抜けない
for 文の中に switch 文を書いたとき、switch の中の break は switch を抜けるだけで、外側の for 文は続きます。 ラベルなしの break は「いちばん内側の switch またはループ」を終える文だからです。
public class SwitchInLoop {
public static void main(String[] args) {
String[] commands = {"add", "quit", "add"};
System.out.print("switch 内の break : ");
for (String c : commands) {
switch (c) {
case "quit":
break; // switch を抜けるだけ。for は続く
default:
System.out.print(c + " ");
}
System.out.print("(次へ) ");
}
System.out.println("| 終了");
System.out.print("ラベル付き break : ");
loop:
for (String c : commands) {
switch (c) {
case "quit":
break loop; // for ごと抜ける
default:
System.out.print(c + " ");
}
System.out.print("(次へ) ");
}
System.out.println("| 終了");
System.out.print("フラグで抜ける : ");
boolean done = false;
for (int i = 0; i < commands.length && !done; i++) {
switch (commands[i]) {
case "quit" -> done = true;
default -> System.out.print(commands[i] + " ");
}
}
System.out.println("| 終了");
System.out.print("switch 内の continue : ");
for (String c : commands) {
switch (c) {
case "quit":
continue; // continue は switch ではなく for に効く
default:
System.out.print(c + " ");
}
System.out.print("(次へ) ");
}
System.out.println("| 終了");
}
}
実行結果:
switch 内の break : add (次へ) (次へ) add (次へ) | 終了
ラベル付き break : add (次へ) | 終了
フラグで抜ける : add | 終了
switch 内の continue : add (次へ) add (次へ) | 終了
| 書き方 | "quit" のときの動き |
|---|---|
switch 内の break; |
switch だけを抜ける。「(次へ)」が出力され、3つ目の add も処理される |
break loop; |
for 文ごと抜ける。3つ目の add は処理されない |
| フラグ変数 | フラグを立て、for 文の条件で終わる |
switch 内の continue; |
for 文の次の回へ進む。「(次へ)」は出力されない |
4つ目の結果も大事な点です。continue は switch には作用せず、外側のループに作用します。 break と continue で対象が違うので、switch をループの中に書くときは「break は switch、continue はループ」と覚えておくと取り違えを防げます。
コマンドを受け取って終了を判定するような処理では、ループと switch を含む部分をメソッドにして return で終える形にすると、ラベルもフラグも要らなくなります。
forEachのラムダ内でbreakは書けない
List の forEach メソッドにラムダ式を渡す書き方では、ラムダ式の中に break や continue を書くとコンパイルエラーになります。 ラムダ式の本体は「1要素ぶんの処理」を表す別のまとまりで、その中にはループがないためです。
import java.util.List;
public class LambdaBreak {
public static void main(String[] args) {
List<Integer> stock = List.of(5, 8, 0, 3);
stock.forEach(n -> {
if (n == 0) break;
System.out.println(n);
});
}
}
LambdaBreak.java:7: error: break outside switch or loop
if (n == 0) break;
^
1 error
error: compilation failed
同じ位置を continue にした場合のエラー文は次のとおりです。
LambdaContinue.java:7: error: continue outside of loop
if (n == 0) continue;
^
1 error
error: compilation failed
代わりの書き方(takeWhile・anyMatch・findFirst・filter)
やりたいことに合わせて、次の書き方に置き換えます。
import java.util.List;
import java.util.Optional;
public class LambdaAlt {
public static void main(String[] args) {
List<Integer> stock = List.of(5, 8, 0, 3);
// ラムダ内の return は「この要素の処理を終える」= continue に相当
System.out.print("forEach + return : ");
stock.forEach(n -> {
if (n == 0) return;
System.out.print(n + " ");
});
System.out.println();
// break に相当 1: takeWhile(条件を満たす間だけ流す。Java 9 以降)
System.out.print("takeWhile : ");
stock.stream().takeWhile(n -> n != 0).forEach(n -> System.out.print(n + " "));
System.out.println();
// break に相当 2: anyMatch(見つかった時点で打ち切る)
System.out.print("anyMatch : ");
boolean hasZero = stock.stream()
.peek(n -> System.out.print("[" + n + "を確認] "))
.anyMatch(n -> n == 0);
System.out.println("→ " + hasZero);
// break に相当 3: findFirst(最初の1件を取り出す)
Optional<Integer> firstBig = stock.stream().filter(n -> n >= 8).findFirst();
System.out.println("findFirst : " + firstBig);
// continue に相当: filter
System.out.print("filter : ");
stock.stream().filter(n -> n != 0).forEach(n -> System.out.print(n + " "));
System.out.println();
// 拡張 for 文なら break がそのまま書ける
System.out.print("拡張 for + break : ");
for (int n : stock) {
if (n == 0) break;
System.out.print(n + " ");
}
System.out.println();
}
}
実行結果:
forEach + return : 5 8 3
takeWhile : 5 8
anyMatch : [5を確認] [8を確認] [0を確認] → true
findFirst : Optional[8]
filter : 5 8 3
拡張 for + break : 5 8
| やりたいこと | 書き方 | 実行結果からわかること |
|---|---|---|
| continue に相当(この要素を飛ばす) | ラムダ内で return; |
0 だけ飛ばして 5 8 3 を出力 |
| continue に相当(条件に合う要素だけ処理) | filter(条件) |
同じく 5 8 3 を出力 |
| break に相当(条件を満たす間だけ処理) | takeWhile(条件)(Java 9 以降) |
0 の手前で止まり 5 8 を出力 |
| break に相当(見つかったら打ち切る) | anyMatch(条件) |
0 を確認した時点で終わり、3 は確認していない |
| break に相当(最初の1件を取り出す) | filter(条件).findFirst() |
Optional で結果を受け取る |
| break をそのまま書きたい | 拡張 for 文 | 5 8 を出力 |
ラムダ式の中の return は、メソッド全体ではなく「その要素の処理」を終えるだけです。そのため forEach では continue と同じ働きになります。forEach を囲むメソッドを終えたいときは、拡張 for 文に書き換えると return がそのまま使えます。
anyMatch の実行結果では、peek で確認した要素を出力しています。0 を見つけた時点で打ち切られ、4つ目の 3 は確認されていません。 「条件に合う要素があるか」を調べる処理は、ループと break で書くよりも anyMatch のほうが意図が伝わりやすくなります。
迷ったときは拡張 for 文で書いて問題ありません。 break・continue・return がそのまま使え、動きも読み取りやすい書き方です。
コンパイルエラー文と直し方の一覧
break と continue に関するコンパイルエラーを、実際に出力されたエラー文でまとめます。日本語のメッセージは、javac を日本語の設定(-J-Duser.language=ja)で実行したときの出力です。
| エラー文(英語) | エラー文(日本語) | 原因 | 直し方 |
|---|---|---|---|
| break outside switch or loop | breakがswitch文またはループの外にあります | ループでも switch でもない場所(if の中だけ、ラムダ式の中など)に break がある | ループの中に書く。ラムダ式なら拡張 for 文や takeWhile に置き換える |
| continue outside of loop | continueがループの外にあります | ループの外、またはラムダ式の中に continue がある | ループの中に書く。ラムダ式なら return; か filter にする |
| undefined label: outer | ラベルouterは未定義です | 指定したラベルが、その文を囲む位置にない | ラベルを外側のループの直前に付ける。名前のつづりを確認する |
| not a loop label: block | blockはループ・ラベルではありません | ループではない文のラベルを continue に指定した | ラベルをループに付ける。ブロックを抜けたいなら break にする |
| unreachable statement | この文に制御が移ることはありません | break や continue の直後に、実行されることのない文がある | break を if で囲むか、後ろの文を前に移す |
1つ目と5つ目のエラーになるコードも載せておきます。
public class Err1 {
public static void main(String[] args) {
int x = 1;
if (x == 1) {
break;
}
}
}
Err1.java:5: error: break outside switch or loop
break;
^
1 error
error: compilation failed
if 文は「ループ」ではないので、if の中に書いた break は、その外側にループか switch がなければエラーになります。if を途中で終えたいときは、条件を分けるか、メソッドにして return を使います。
public class Err3 {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
break;
System.out.println(i);
}
}
}
Err3.java:5: error: unreachable statement
System.out.println(i);
^
1 error
error: compilation failed
条件を付けずに break を書くと、その後ろの文は実行されることがありません。Java はこれをコンパイルの時点で知らせてくれます。
どれを使うかの判断表
| 状況 | 選ぶ書き方 |
|---|---|
| 目的のものが見つかったのでループを終えたい | break; |
| この回の処理だけ飛ばしたい | continue; |
| 二重ループを一度に終えて、後ろの処理を続けたい | ラベル付き break |
| 内側のループの途中で、外側の次の回へ進みたい | ラベル付き continue |
| 探して結果を返すだけ | メソッドにして return 値; |
| ループ内の switch からループを終えたい | ラベル付き break、またはメソッドにして return |
| forEach のラムダで途中で止めたい | 拡張 for 文、takeWhile、anyMatch、findFirst |
| forEach のラムダで一部を飛ばしたい | return; または filter |
| while で一部を飛ばしたい | 更新を先に書いてから continue。回数が決まっているなら for 文 |
読みやすさの面では、次のような目安があります。
- 飛ばす条件はループの先頭にまとめると、「この後は条件を満たした要素だけを扱う」ことが伝わります(ガード節と呼ばれる書き方です)。
- ラベル名は役割を表す名前にします。search や next のように、何のためのループかがわかる名前が向いています。
- 三重以上のループでラベルが増えてきたら、メソッドに分ける合図です。内側の処理をメソッドにすると、return だけで済むようになります。
よくある質問
Q. break と continue の違いは何ですか? A. break はループそのものを終え、continue は今の回の残りを飛ばして次の回へ進みます。1〜5 のループで 3 のときに実行すると、break は「1 2」、continue は「1 2 4 5」が出力されます。
Q. 二重ループを一度に抜けるにはどうしますか?
A. 外側のループの直前に outer: のようなラベルを付け、内側で break outer; と書きます。探索の結果を返すだけなら、二重ループをメソッドに切り出して return する方法も読みやすい書き方です。
Q. break と return はどう違いますか? A. break はループを終えて、ループの後ろの処理へ進みます。return はメソッドを終えるので、ループの後ろに書いた処理も実行されません。
Q. forEach の中で break や continue は使えますか?
A. ラムダ式の中には書けません(break outside switch or loop、continue outside of loop というコンパイルエラーになります)。continue の代わりはラムダ内の return; か filter、break の代わりは拡張 for 文・takeWhile・anyMatch・findFirst です。
まとめ
- break はループを終える、continue は今の回を飛ばして次の回へ進む
- ラベルなしの break / continue は、いちばん内側のループに作用する。 二重ループをまとめて抜けるならラベル付き break
- return はメソッドを終える。 ループの後の処理も実行されない点が break との違い
- while で continue するときは、カウンタの更新を先に済ませる。 回数が決まっているなら for 文にする
- switch の中の break は switch を抜けるだけ。 continue は外側のループに作用する
- ラムダ式の中に break / continue は書けない。 拡張 for 文、takeWhile、anyMatch、findFirst、filter に置き換える
- エラー文(break outside switch or loop など)は、書いた位置がループの中かどうかを確認する手がかりになる
参考・出典
- Oracle「The Java Language Specification, Java SE 21 Edition」第14章(14.15 The break Statement、14.16 The continue Statement): https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Javaのbreakとcontinueの使い方|ラベルで二重ループを抜ける」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。