実務チートシート:break の使い方 + Stream API への書き換え対比
使い方/例/対比をすぐ現場で使える形でまとめました。コピーしてそのままプロジェクトのコメントやノートに貼れます。
概要
break:ループ内で実行するとそのループを即終了し、ループの外側(次の処理)へ移る。- ネスト内の
breakはその書かれたループだけを抜ける。外側まで抜けたいときは ラベル付きbreakを使う。 - Stream では
findFirst()/anyMatch()/filter()等を使い早期終了に近い処理を書ける。ただし ラベル付き break 相当の外側ループまで一気に抜ける制御はできない(必要ならループで書くかメソッド分割)。
目次
- ASCII 図:
breakのイメージ - 実務パターン 5 + コード(for版 / Stream版)
- ベストプラクティス(ログ・例外・後処理)
- すぐ使えるテンプレート集(抜粋)
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;
}
}
JavaStream版(置き換え可能)
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("最大リトライ失敗");
}
JavaStream版(あまり向かない — 明示的にループが読みやすい)
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();
JavaStream版
ユーザー入力のような副作用ループは 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; // 外側も含めて一気に抜ける
}
}
}
JavaStream での代替(例:フラット化)
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();
JavaStream版(ログを組み合わせる場合)
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;
}
}
}
Java5. よくある質問(FAQ)
- Q
breakとreturnの違いは? - A
breakはループを抜けるだけ。returnはメソッドを終了して呼び出し元に戻る。処理の粒度で使い分ける。
- Q
continueとどう違う? - A
continueはその繰り返しをスキップして次の繰り返しへ(ループは続く)。breakはループ自体を終了。
- QStream で完全に同じ制御は書けますか?
- A
単純検索や anyMatch/findFirst は簡単に置換可能。ただしネストのラベル付き break 相当の「外側も含めて一気に抜ける」制御や、I/O を伴う逐次処理は 読みやすさ優先で for/while を残すことが実務では多いです。
まとめ
- シンプルな検索や早期終了には
breakが強い味方。 - 可読性・副作用・並列性を考えて、必要なら Stream やライブラリ(RetryTemplate, Resilience4j)へ置き換える。
