WisdomSoft - for your serial experiences.

3.8 break文とcontinue文

繰り返し文の制御内から、強制的に抜け出したり、現在の実行を終了して次の反復処理に移行する方法を紹介します。

3.8.1 制御を強制的に抜け出す

3.3 switch文」で、case ブロックから抜け出す方法として break 文を少しだけ解説しました。break 文には、現在のブロックから強制的に抜け出し、外側に制御を移行するという働きがあります。ただし、break 文を記述できるのは switch 文、while 文、do 文、for 文の内部のみです。それ以外の場所で break 文を指定しても、コンパイル・エラーとなるでしょう。

break 文は様々な利用方法があります。列挙された何らかの要素を分析している途中に必要な結果が得られた場合、残りの処理は必要ないので、途中で繰り返し制御を抜け出すことによって処理を最適化したり、繰り返し文で処理しているブロックで、何らかのエラーが発生した時に、制御を抜け出す手段として使う方法が考えられます。

コード1
class Test {
	public static void main(String args[]) {
		int i = 0;
		while(true) {
			if (i >= 5) break;
			String str = "カウンタ = " + i;
			System.out.println(str);
			i++;
		}
		System.out.println("制御から抜け出しました");
	}
}
実行結果
>java Test
カウンタ = 0
カウンタ = 1
カウンタ = 2
カウンタ = 3
カウンタ = 4
制御から抜け出しました

コード1の while 文は、条件に true を指定してるため無限ループと化しています。通常、無限ループは強制終了しない限り、半永久的にブロックを実行し続けます。このプログラムでは、制御を抜け出す手段として break 文を使っていることがわかります。カウンタ用の変数 i が 5 以上になれば break 文が実行されるため、while 文から制御を抜け出すことができます。do 文や for 文でも同様の結果を得ることができます。

3.8.2 ラベル付き文

break 文を使えば、break 文が記述されたブロックを抜け出すということがコード1で証明されましたが、入れ子構造になっている複雑な流れ制御の中では、どのように働くのでしょう。for 文の中に while 文や switch 文などが記述されるなど、流れ制御が複雑に絡み合うことも珍しくありません。

どのような複雑な状態にあっても、break 文はそれが記述された最も内側の制御文に対して機能すると定められています。このような break の対象になる文をブレーク・ターゲットと呼びます。

while(exp1) {
	while(exp2) {
		break;
	}
}

このような、二重の繰り返し制御の中で break 文が指定された場合、ブレーク・ターゲットは最も内側の制御に働きます。つまり、この場合は while(exp2) の制御から抜け出すことになるのです。

ところが、目的が制御全体から抜け出す場合は、いささか面倒です。ループにループを重ねた複雑な処理の最下層部で致命的なエラーが発生したとしても正常にプログラムが終了できるように仕組むのは困難です。C/C++ 言語であれば、最後の手段となる goto 文を使って強制的に適当な位置に移動することができましたが、Java 言語では安全性に問題がある goto 文は使えません。

この問題を解決するには、ラベル付き文を使います。ラベル付き文とは、文に名前をつけることによって、一種のマーキングを行います。ラベル付き文を記述することによって、識別子で文を指定できるのです。ラベル付き文は、次のような構文になります。

ラベル付き文
ラベル識別子 : 

ラベル識別子には、変数などと同様に Java の識別子命名規則にしたがって、対象の文のラベルを指定します。ラベル識別子のスコープは、対象の文のみです。文から抜け出した時点で、ラベルは無効となります。そのため、ラベル付き文はブロックとなり、ブロックの中でこの識別子が利用されることになるでしょう。

break 文は、ブレーク・ターゲットをラベルで指定することができます。正式な break 文の構文は次のような形です。

break文
break ラベル;

ラベルは省略可能です。ラベルを省略した break 文は、最も内側の制御文がブレーク・ターゲットとなります。ラベルを指定すると、指定したラベルに等しい識別子のラベル付き文がブレーク・ターゲットとなります。ラベルを指定することによって、特定の階層まで一気に抜け出すことが可能となります。

コード2
class Test {
	public static void main(String args[]) {
		Layer1 : for(int i = 0 ; ; i++) {
			System.out.println("Layer1 ブロック");
			Layer2 : while(true) {
				System.out.println("\tLayer2 ブロック");
				if (i < 4) {
					System.out.println("\tLayer2 から抜け出す");
					break Layer2;
				}
				else {
					System.out.println("Layer1 から抜け出す");
					break Layer1;
				}
			}
		}
	}
}
実行結果
>java Test
Layer1 ブロック
        Layer2 ブロック
        Layer2 から抜け出す
Layer1 ブロック
        Layer2 ブロック
        Layer2 から抜け出す
Layer1 ブロック
        Layer2 ブロック
        Layer2 から抜け出す
Layer1 ブロック
        Layer2 ブロック
        Layer2 から抜け出す
Layer1 ブロック
        Layer2 ブロック
Layer1 から抜け出す

コード2では、トップレベルの for 文に対して Layer1 というラベルを与え、for 文の制御にある while 文に対して Layer2 というラベルを与えています。どちらの繰り返し文も共に無限ループとなっているため、制御から抜け出す手段は break 文を使うしかありません。このプログラムでは、while 文から、その親である for 文の制御を抜け出す手段として、ラベルを指定した break 文を使っています。

break Layer2; は、while 文がブレーク・ターゲットとなりますが、そもそも while 文は最も内側の制御なので、ラベルを省略しても同じ結果が得られます。重要なのは、その上の for 文を抜け出すために使われている break Layer1; という文です。Layer1 というラベルは for 文に適用されているため、この break 文のブレーク・ターゲットは for 文となるのです。

3.8.3 次の繰り返しへ

繰り返し処理を行っている途中で、これ以上コードを実行する必要がなくなるなどの事情で次の繰り返しに移行したい場合は continue 文を使います。多くのケースでは if 文を使うことによって制御を分けられるため continue 文を使わなくても表現できないわけではありませんが、continue 文を使うことでソースをスマートにしたり、break のようにラベルを使って、特定階層の繰り返し文まで戻ることも可能です。

continue 文
continue ラベル;

基本的な考え方は break 文と同じです。ラベルは省略することが可能で、省略された場合は continue 文が記述された最も内側の制御から抜け出します。ラベルが指定された場合は、これと同一の識別子を持つラベル付き文が対象となります。このとき、continue 文の対象となる文を継続ターゲットと呼びます。

continue 文は、繰り返し制御の次のステップに移行するという性質を持つため、必ず while 文、do 文、for 文の制御内で使われなければなりません。そうでなければ、継続ターゲットが見つからないため、コンパイル・エラーとなります。

コード3
class Test {
	public static void main(String args[]) {
		String str = "";	//確実な代入
		for(int i = 1 ; ; i++) {
			if ((i % 2) != 0) continue;

			if (i < 10) str += " " + i + " ";
			else str += i + " ";
			if (i == 100) break;
			else if (i != 0 && (i % 20) == 0) str += '\n';
		}
		System.out.println(str);
	}
}
実行結果
>java Test
 2  4  6  8 10 12 14 16 18 20
22 24 26 28 30 32 34 36 38 40
42 44 46 48 50 52 54 56 58 60
62 64 66 68 70 72 74 76 78 80
82 84 86 88 90 92 94 96 98 100

コード3は、continue 文の働きを証明するためのプログラムです。for 文ではカウント変数 i を宣言し、これをインクリメントしながら無限にループします。プログラムでは str 変数に偶数の値のみを代入していくことを目的とし、奇数であれば continue 文によって次の繰り返しに移行します。i % 2 を求め、余りが 0 であれば i が偶数、そうでなければ奇数であることを証明できます。continue 文が実行されれば、プログラムは for 文まで復帰し、更新式と条件式を評価して再びブロックを実行します。