Java | break 文の使い方

Java Java
スポンサーリンク

実務チートシート:break の使い方 + Stream API への書き換え対比

使い方/例/対比をすぐ現場で使える形でまとめました。コピーしてそのままプロジェクトのコメントやノートに貼れます。


概要

  • break:ループ内で実行するとそのループを即終了し、ループの外側(次の処理)へ移る。
  • ネスト内の breakその書かれたループだけを抜ける。外側まで抜けたいときは ラベル付き break を使う。
  • Stream では findFirst() / anyMatch() / filter() 等を使い早期終了に近い処理を書ける。ただし ラベル付き break 相当の外側ループまで一気に抜ける制御はできない(必要ならループで書くかメソッド分割)。

目次

  1. ASCII 図:break のイメージ
  2. 実務パターン 5 + コード(for版 / Stream版)
  3. ベストプラクティス(ログ・例外・後処理)
  4. すぐ使えるテンプレート集(抜粋)

1. ASCII 図:break のイメージ

[ループ開始]
   |
  [処理]
   |
  (条件?)---Yes---> [break] ---> [ループを抜けて次の処理へ]
   | No
  [次の繰り返し]
   |
 [ループ終了]

ネスト時:

OuterLoop:
 for i...
   |
  InnerLoop:
   for j...
     |
    (条件?)---Yes---> break        // only inner loop exits
     |
   next j
   |
 next i

// ラベル付き: break Outer; なら OuterLoop まで一気に抜ける

2. 実務パターン 5(コード表:for/while と Stream 対比)

パターン①:検索処理(最初に見つけたら終了)

用途:リスト・配列から最初に一致する要素だけ探す(検索)

for版(典型)

String target = "Charlie";
List<String> users = List.of("Alice","Bob","Charlie","David");
for (String name : users) {
    if (name.equals(target)) {
        System.out.println("見つけた: " + name);
        break;
    }
}
Java

Stream版(置き換え可能)

Optional<String> found = users.stream()
                              .filter(name -> name.equals(target))
                              .findFirst();
found.ifPresent(name -> System.out.println("見つけた: " + name));
Java

ポイント:Stream は表現が短く、並列化も効く。単純検索は findFirst() 推奨。


パターン②:リトライ処理(成功したら抜ける)

用途:外部API・ネットワーク接続で複数回リトライ

for版(典型)

final int MAX = 3;
for (int i = 1; i <= MAX; i++) {
    if (tryCall()) {
        System.out.println("成功");
        break;
    }
    if (i == MAX) System.err.println("最大リトライ失敗");
}
Java

Stream版(あまり向かない — 明示的にループが読みやすい)

Stream はリトライロジックには向かないため、ループで書くのが実務的。
(Spring の RetryTemplate や Resilience4j の使用が現場では多い)

ポイント:リトライは明示的なループ or ライブラリを使う。


パターン③:ユーザー入力の検証ループ

用途:CLI 等で正しい入力が来るまで再入力させる

while + break(典型)

Scanner sc = new Scanner(System.in);
while (true) {
    System.out.print("年齢を入力: ");
    int age = sc.nextInt();
    if (age >= 0 && age <= 120) {
        System.out.println("OK: " + age);
        break;
    }
    System.out.println("不正な値。再入力してください。");
}
sc.close();
Java

Stream版

ユーザー入力のような副作用ループは Stream に向かない。while の方が明確。

ポイント:副作用(I/O)を伴う反復はループで書く。


パターン④:ネストされたループでの外側も抜けたい(ラベル付き break)

用途:二重ループで「見つけたら全部抜ける」

ラベル付き break(典型)

Outer:
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        if (matrix[i][j] == target) {
            System.out.println("発見: " + i + "," + j);
            break Outer; // 外側も含めて一気に抜ける
        }
    }
}
Java

Stream での代替(例:フラット化)

IntStream.range(0, rows)
  .flatMap(i -> IntStream.range(0, cols)
        .map(j -> i * cols + j))
  .filter(idx -> {
      int i = idx / cols, j = idx % cols;
      return matrix[i][j] == target;
  })
  .findFirst()
  .ifPresent(idx -> System.out.println("発見: " + (idx / cols) + "," + (idx % cols)));
Java

注意:Stream の書き方は可読性が落ちる場合がある。ラベル付き break の方が直感的なケースも多い。


パターン⑤:異常値/不正検出で早期終了(ログ付き)

用途:データ処理中に不整合を見つけたら中断して調査する

for版(典型)

for (Record r : records) {
    if (!r.isValid()) {
        logger.error("不正データ: id=" + r.getId());
        break;
    }
    process(r);
}
cleanup();
Java

Stream版(ログを組み合わせる場合)

boolean hadInvalid = records.stream()
    .peek(r -> { if (!r.isValid()) logger.error("不正: " + r.getId()); })
    .anyMatch(r -> !r.isValid());

if (!hadInvalid) {
    records.forEach(this::process);
}
cleanup();
Java

ポイントpeek は副作用的なので注意。責務を分けた方が安全(バリデーション → 問題なければ処理)。


3. 実務ベストプラクティス(チェックリスト)

  • break を使う前に「メソッドに切り出せないか」を検討する(可読性向上)。
  • ラベル付き break は便利だが 乱用厳禁。可読性を損なうなら return でメソッドを抜ける、またはフラグを使う。
  • ループ内で break を使う場合、必要な後処理(close, unlock, ログ等)が確実に実行されるかを確認する。try-with-resources / finally を使う。
  • 並列処理では break が意味をなさない(スレッドごとのループを止めるだけ)。並列処理時は Future.cancel() やフラグ、並行制御を使う。
  • Stream に置き換えるときは「副作用の有無」を検討:副作用あり(I/O・ログ・状態変更)はループのままの方が分かりやすいことがある。
  • ログは「何を検出してなぜ中断したか」を明確に残す(ID・行番号などを出す)。

4. すぐ使えるテンプレート(コピーして使える)

テンプレートA:検索+結果フラグ

boolean found = false;
for (Type t : collection) {
    if (matches(t)) {
        // 何か処理
        found = true;
        break;
    }
}
if (!found) {
    // 見つからなかった場合の処理
}
Java

テンプレートB:リトライ(最大回数)

final int MAX_RETRY = 3;
for (int attempt = 1; attempt <= MAX_RETRY; attempt++) {
    try {
        if (doOperation()) {
            // 成功
            break;
        }
    } catch (IOException e) {
        logger.warn("試行" + attempt + "で例外", e);
    }
    if (attempt == MAX_RETRY) {
        // 最終失敗時の処理
    } else {
        Thread.sleep(1000); // バックオフ
    }
}
Java

テンプレートC:ラベル付き(慎重に)

Outer:
for (...) {
    for (...) {
        if (condition) {
            // ログ残す等
            break Outer;
        }
    }
}
Java

5. よくある質問(FAQ)

Q
breakreturn の違いは?
A

breakループを抜けるだけ。returnメソッドを終了して呼び出し元に戻る。処理の粒度で使い分ける。

Q
continue とどう違う?
A

continueその繰り返しをスキップして次の繰り返しへ(ループは続く)。breakループ自体を終了

Q
Stream で完全に同じ制御は書けますか?
A

単純検索や anyMatch/findFirst は簡単に置換可能。ただしネストのラベル付き break 相当の「外側も含めて一気に抜ける」制御や、I/O を伴う逐次処理は 読みやすさ優先で for/while を残すことが実務では多いです。


まとめ

  • シンプルな検索や早期終了には break が強い味方。
  • 可読性・副作用・並列性を考えて、必要なら Stream やライブラリ(RetryTemplate, Resilience4j)へ置き換える。
Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました