Javaでネストされた複数のループから一括で脱出する方法

こんにちは。ゆうせいです。

新人研修中に受講者から以下の質問をいただきました。

多重ループで一番内側のループから一気に一番外側のループを脱出方法はありますか?

今回はこの質問に答えたいと思います。

プログラムを作成していると、ループの中にさらにループがある「多重ループ(ネスト)」という構造が必要になる場面があります。特定の条件を満たしたときに、現在実行している内側のループだけでなく、その外側にあるすべてのループから一度に抜け出したい場合があります。Java言語において、この挙動を実現するための最も一般的な手法はラベル付きbreak文です。

多重ループの構造と脱出の課題

Javaの基本的なbreak文は、現在実行されている最も内側のループ1つ分しか終了させることができません。

例えば、ホテルのすべての部屋を順番に掃除している場面を想像してください。

1階から5階まであり(外側のループ)、各階に10部屋(内側のループ)あるとします。

もし3階の5号室を掃除している最中に「建物全体で緊急事態が発生したので、すべての掃除を即座に中断して外に出る」必要がある場合、通常のbreak文では3階の掃除を止めることしかできず、自動的に4階の掃除が始まってしまいます。

このように、複数の階層を一気に飛び越えて外に出るための仕組みが必要です。

ラベル付きbreak文による解決

Javaでは、ループの直前に任意の名前(ラベル)を付けることで、break文の対象をそのラベルが指すループに指定できます。

具体的な実装例

以下のコードは、2重のforループから特定の条件で一括脱出する例です。

public class LoopExitSample {
    public static void main(String[] args) {
        outerLoop:
        for (int i = 1; i <= 5; i++) {
            for (int j = 1; j <= 10; j++) {
                if (i == 3 && j == 5) {
                    System.out.println("3階5号室で中断条件に合致しました。すべてのループを終了します。");
                    break outerLoop;
                }
                System.out.println(i + "階" + j + "号室を処理中");
            }
        }
        System.out.println("ループの外に出ました。");
    }
}

専門用語の解説と比喩

ラベル付きbreak文

ループの開始地点に目印(ラベル)を貼り、その目印を指定して脱出する命令です。これは「避難経路の指定」に例えることができます。通常のbreak文が「今いる部屋のドアを開ける」だけなのに対し、ラベル付きbreak文は「指定された非常口(ラベル)まで一気に駆け抜ける」役割を果たします。

メリットとデメリット

事実として確認できる利点と欠点は以下の通りです。

メリット

  1. 階層の数に関わらず、一度の命令で最外周まで脱出できるため、フラグ変数(後述)を用いた複雑な条件分岐を省略でき、コードが簡潔になります。
  2. 実行速度において、余計な条件判定を挟まずにジャンプするため、わずかながら効率的です。

デメリット

  1. プログラムの実行順序が大きく飛ぶため、過度に使用すると処理の流れが追いにくくなる可能性があります。
  2. 他のプログラミング言語(C言語やPythonなど)では採用されていない場合が多く、言語固有の作法として学習コストが生じます。

その他の代替手法

ラベルを使用しない方法として、フラグ変数を利用する手法があります。

フラグ変数

「処理を続けるかどうか」を管理する、真偽値(boolean型)の変数のことです。これは「信号機」に例えられます。内側のループで異常を検知した際に信号を「赤」に変え、外側のループがその信号を見て自分も停止するという連鎖的な停止方法です。

安全で分かりやすい一方、各ループの階層で毎回「信号は赤になっていないか」を確認する記述が必要になるため、コードの量が増加します。

フラグ変数による多重ループ脱出の実装

フラグ変数を用いる場合、内側のループで特定の条件を満たしたときに変数の値を書き換え、その直後にbreakします。さらに、外側のループでもその変数の値をチェックし、必要に応じて再度breakを行うという二段構えの構成をとります。

具体的な実装例

以下のコードは、フラグ変数を用いて2重ループを終了させる例です。

public class LoopFlagSample {
    public static void main(String[] args) {
        boolean isFinished = false;

        for (int i = 1; i <= 5; i++) {
            for (int j = 1; j <= 10; j++) {
                if (i == 3 && j == 5) {
                    System.out.println("3階5号室で中断条件に合致しました。フラグを立てて内側を抜けます。");
                    isFinished = true;
                    break;
                }
                System.out.println(i + "階" + j + "号室を処理中");
            }

            if (isFinished) {
                System.out.println("フラグが立っているため、外側のループも終了します。");
                break;
            }
        }
        System.out.println("ループの外に出ました。");
    }
}

専門用語の解説と比喩

フラグ(flag) 「旗」を意味する用語で、特定の状態になったかどうかを記録するための変数です。高校の体育祭の旗取り競争に例えると分かりやすいでしょう。内側のループという競技エリアで「旗」を手に取り、それを見た外側の進行係(外側のループ)が「競技終了」を宣言するという流れになります。

メリットとデメリット

この手法の特徴は以下の通りです。

メリット

  1. Java以外の多くのプログラミング言語でも共通して利用できる論理構造であるため、汎用性が非常に高いです。
  2. 処理の中断理由が「isFinished」や「hasError」といった変数名に現れるため、なぜループを抜けたのかという意図が第三者に伝わりやすくなります。

まとめと学習のステップ

多重ループから一気に抜けるには、ラベル付きbreak文がJavaにおける標準的かつ効率的な解決策です。学習を深めるためのステップを以下に示します。

  1. まずは通常のbreak文とcontinue文の挙動を、1重のループで完全に理解してください。
  2. 次に2重ループを作成し、内側でのbreakが外側に影響を与えないことをコードを書いて確認してください。
  3. ラベル付きbreak文を導入し、実行結果がどのように変化するかを観察してください。
  4. 最後に、フラグ変数を使った場合とラベルを使った場合で、コードの読みやすさがどう変わるかを比較検討してみてください。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。