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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?