Java | 基礎文法:無限ループ

Java Java
スポンサーリンク

無限ループの全体像

無限ループは「終了条件が永遠に満たされず、ループが止まらない状態」です。Java では while (true)for(;;) のように意図的に書くこともできますが、初心者が陥りやすいのは「終了条件の設計ミス」「状態更新の漏れ」「比較の取り違え」です。止まらないだけでなく、CPU を占有してアプリ全体を固めることもあるため、原因と対策を体系的に押さえることが大切です。


典型的な発生原因

終了条件が間違っている、または到達不能になっていると止まりません。更新が分岐で飛ぶ、continue で更新箇所をスキップする、浮動小数点の誤差で「いつまでも条件が真」のままになる、といった落とし穴が代表例です。入力待ちやブロッキング I/O で「止まらないように見える」ケースもあり、無限ループと見分ける必要があります。


よくあるコード例と直し方

状態更新の漏れ

int i = 0;
while (i < 3) {
    System.out.println(i);
    // i++ がない → 永遠に i は 0 のまま
}
Java

更新は必ず通る構造にします。本体の最後に置くか、分岐があるならどの分岐でも更新が走るようにします。

int i = 0;
while (i < 3) {
    System.out.println(i);
    i++;
}
Java

終了条件の取り違え(比較の向き)

int remain = 3;
while (remain >= 0) { // 0 でも入るので、更新次第では無限ループに
    System.out.println(remain);
    remain--;         // -1, -2... と続いて抜けない
}
Java

「減らすなら 0 より大きい」「増やすなら未満」を基本形にそろえると安定します。

int remain = 3;
while (remain > 0) {
    System.out.println(remain);
    remain--;
}
Java

continue で更新が飛ぶ

int i = 0;
while (i < 5) {
    if (i == 2) {
        continue; // ここで i++ を飛ばす → i==2 のまま無限ループ
    }
    System.out.println(i);
    i++;
}
Java

continue 前に更新を入れるか、更新を先頭へ寄せます。

int i = 0;
while (i < 5) {
    if (i == 2) { i++; continue; }
    System.out.println(i);
    i++;
}
Java

浮動小数点の比較

double x = 0.0;
while (x != 1.0) { // 誤差で 1.0 に「ちょうど」ならない可能性
    x += 0.1;
}
Java

誤差を考慮した条件にします。イプシロンを使う、または回数で制御します。

double x = 0.0;
while (Math.abs(x - 1.0) > 1e-9) {
    x += 0.1;
    if (x > 2.0) break; // セーフティ
}
Java

入力待ちで進まない(無限ループと誤解)

java.io.BufferedReader br = ...;
String line;
while ((line = br.readLine()) != null) {
    // 入力が来ないとここでブロックし続ける(停止ではなく待機)
}
Java

「待機」と「無限」を区別します。タイムアウトや番兵値(空行など)で終了条件を明示すると把握しやすくなります。


安全弁の設計(深掘り)

試行回数の上限

上限で必ず止める発想です。「成功するまで、ただし N 回まで」にすると、失敗時でも脱出できます。

int attempts = 0, max = 3;
boolean success = false;
while (!success && attempts < max) {
    success = tryOnce();
    attempts++;
}
Java

時間上限(締切)

「一定時間が過ぎたら終了」。時間は「最初に測る」「各周回でチェック」のセットで。

long deadline = System.nanoTime() + 1_000_000_000L; // 1秒
while (workRemaining()) {
    step();
    if (System.nanoTime() > deadline) break;
}
Java

番兵値・hasNext の活用

入力が尽きたら終了、特定の値で終了、といった「出口」を条件に直書きすると安全です。

java.util.Scanner sc = new java.util.Scanner("10 20 30");
int sum = 0;
while (sc.hasNextInt()) {
    sum += sc.nextInt();
}
Java

進捗チェックとスピン抑制

「何も進んでいない」周回が続くなら抜けるか休む。CPU 暴走を防ぎます。

int prev = state();
while (true) {
    doWork();
    int cur = state();
    if (cur == prev) { Thread.sleep(1); } // 進捗なしなら休む
    prev = cur;
}
Java

早期終了の道具と使い分け

break・return・ラベル付き break

  • ループだけ終わらせたいなら break
  • メソッドごと終わらせたいなら return
  • 多重ループをまとめて抜けたいならラベル付き break
outer:
for (int r = 0; r < R; r++) {
    for (int c = 0; c < C; c++) {
        if (found(r, c)) break outer; // 外側まで一気に脱出
    }
}
Java

「どこまで止めたいか」を軸に選ぶと、フローが明快になります。


調査・デバッグのコツ

ループの上限やタイムアウトを仮で入れ、進捗ログ(周回番号、主要変数)を出すと原因が見えます。境界テスト(空入力、1件、大量、先頭・末尾)で終了条件を揺さぶるのが有効です。インクリメント/デクリメントを式に混ぜず、更新位置を一箇所に固定すると追いやすくなります。


実用例で総復習

線形探索で「見つかったら終わり」

public class FindFirst {
    public static void main(String[] args) {
        String[] names = {"abe", "sato", "suzuki", "sakai"};
        String found = null;
        for (String n : names) {
            if (n.startsWith("sa")) { found = n; break; }
        }
        System.out.println(found); // sato
    }
}
Java

ログ読みで「空行まで」

import java.util.Scanner;
public class UntilBlank {
    public static void main(String[] args) {
        Scanner sc = new Scanner("A\nB\n\nC\n");
        String line;
        while ((line = sc.nextLine()) != null && !line.isBlank()) {
            System.out.println("read: " + line);
        }
        System.out.println("stop at blank");
    }
}
Java

リトライ+上限の安全弁

public class Retry {
    public static void main(String[] args) {
        int attempts = 0, max = 3;
        boolean ok;
        do {
            ok = tryOnce();
            attempts++;
        } while (!ok && attempts < max);
        System.out.println(ok ? "OK" : "NG");
    }
    static boolean tryOnce() { return Math.random() < 0.4; }
}
Java

仕上げのアドバイス(重要部分のまとめ)

終了条件は「比較軸」と「更新軸」をペアで設計し、更新が必ず通る構造にします。continue を使う分岐でも更新一貫性を保ち、浮動小数点はイプシロンか回数制御で安全に。実務では「回数上限」「時間上限」「番兵値」を積み、必要なら break/return/ラベル付き break で早期終了を明確化します。進捗ログと境界テストで原因を特定し、CPU スピンは休ませる。この流儀を守れば、無限ループは怖くありません。

タイトルとURLをコピーしました