【脱スパゲッティコード!Javaでbreakとcontinueを使わない書き方と、その是非について
こんにちは。ゆうせいです。
プログラミングの勉強は順調に進んでいますか。Javaの学習が進むと、for文やwhile文といった繰り返し処理が出てきますね。そこで必ずと言っていいほど登場するのが、breakとcontinueという命令です。
これらは非常に便利ですが、現場の先輩や研修の講師から「あまり使いすぎるな」とか、あるいは極端に「禁止」と言われた経験はないでしょうか。
新人エンジニアの皆さんがふと疑問に思うこと。それは「そもそも、breakやcontinueを使わずにコードを書くことは可能なのか?」という点です。
今日は、この疑問に対して、現役エンジニアの視点から優しく、そして深く解説していきます。一緒に、美しいコードの世界への第一歩を踏み出しましょう。
breakとcontinueの役割を再確認しよう
まずは、これらが何をしているのか、イメージを共有しましょう。難しい言葉は使いません。
高校のマラソン大会を想像してください。あなたは校庭を10周走らなければなりません。これがループ(繰り返し処理)です。
breakとは
breakは「中断」です。
5周目を走っている途中で、突然先生が「はい、終了!みんな教室に戻って!」と叫んだとします。あなたは残りの5周を走ることなく、その場でマラソンを辞めて教室に向かいますよね。これがbreakの動きです。ループの条件(10周走る)が満たされていなくても、強制的にループから脱出します。
continueとは
continueは「スキップ」です。
3周目を走っているとき、水たまりがありました。「この周は走ったことにして、次の周のスタート地点までワープしよう」というのがcontinueです。マラソン自体は終わりませんが、その周の残りの処理(コースを走るなど)を飛ばして、次の周回(4周目)の先頭から再開します。
どちらも、ループの流れを強制的に変える強力な命令です。
breakを使わずに書く方法
では、本題に入りましょう。これらを使わずにプログラムを書くことはできるのでしょうか。
答えは「YES」です。
まずはbreakを使わない書き方を見てみましょう。例として、数字がたくさん入ったリストから、特定の数字「7」を見つけるプログラムを考えます。
breakを使った場合
通常は、見つかった瞬間にbreakしてループを抜けます。
int[] numbers = {1, 3, 5, 7, 9};
boolean found = false;
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == 7) {
found = true;
break; // 見つかったので抜ける
}
}
breakを使わない場合
breakを使わないためには、フラグと呼ばれる目印を使ったり、ループの継続条件を工夫したりします。
int[] numbers = {1, 3, 5, 7, 9};
boolean found = false;
int i = 0;
// 見つかっていない間だけループするという条件にする
while (i < numbers.length && found == false) {
if (numbers[i] == 7) {
found = true;
}
i++;
}
どうでしょうか。for文の条件式部分に found == false という条件を加えることで、「見つかったらループが終わる」という制御を実現しています。これなら、強制的な中断命令を使わずに済みますね。
continueを使わずに書く方法
次に、continueを使わない書き方です。例として、1から5までの数字のうち、偶数だけを画面に表示するプログラムを考えます。
continueを使った場合
奇数ならスキップする、というロジックになります。
for (int i = 1; i <= 5; i++) {
if (i % 2 != 0) {
continue; // 奇数なら以下の処理をスキップ
}
System.out.println(i);
}
continueを使わない場合
これは、if-else文(もし〜なら)を使って、条件に合うときだけ処理をするように書き換えます。
for (int i = 1; i <= 5; i++) {
// 偶数のときだけ実行する
if (i % 2 == 0) {
System.out.println(i);
}
}
いかがですか。「スキップする」のではなく、「対象のときだけ実行する」という発想の転換です。これでcontinueを排除できました。
なぜ「使わないほうがいい」と言われることがあるのか
書き換えが可能なら、なぜわざわざ「使わない」という選択肢があるのでしょうか。
それは、構造化プログラミングという考え方が関係しています。
プログラムの流れは、上から下へと川のように流れるのが理想です。しかし、breakやcontinueは、その流れを急に断ち切ったり、上流に戻したりする「ワープ装置」のようなものです。これらを多用すると、コードを読んでいる人が「あれ?今どこに飛んだんだ?」と迷子になりやすくなります。
特に、ループが二重、三重になっているときにbreakやcontinueが乱用されると、コードの見た目がスパゲッティのように絡まり合い、解読が困難になります。これをスパゲッティコードと呼びます。恐ろしい名前ですね。
無理に排除することのデメリット
しかし、ここで注意が必要です。「絶対に使うな」というのは極論です。無理に排除しようとすると、逆に読みづらくなることがあります。
ネスト(入れ子)が深くなる
先ほどのcontinueを使わない例を思い出してください。if文の中に処理を書きましたね。もし条件が複雑になると、if文の中にif文が入り、さらにその中に...と、文章がどんどん右側にずれていきます。これを「ネストが深くなる」と言い、非常に読みづらいコードの代表例です。
余計な変物が増える
breakを使わない例では、foundのようなフラグ変数を管理する必要がありました。変数は少なければ少ないほどバグ(不具合)の原因が減ります。無理にbreakを避けて変数を増やすのは、本末転倒になることもあります。
真の解決策:メソッドに切り出す
では、私たちはどうすればいいのでしょうか。
breakやcontinueを使うべきか、使わざるべきか。その論争を終わらせるスマートな方法があります。
それは、処理をメソッド(小さな部品)に切り出すことです。
先ほどの「数字の7を探す」処理を見てみましょう。
boolean containsSeven(int[] numbers) {
for (int n : numbers) {
if (n == 7) {
return true; // 見つかった時点で値を返して終了
}
}
return false;
}
ここでのreturnは、breakよりも強力な脱出装置ですが、メソッドという枠組みの中で使う分には非常に自然です。「結果が出たので報告して終わる」という明確な意図が伝わるからです。
メリットとデメリットのまとめ
最後に、breakやcontinueを使わない書き換えについて整理しましょう。
メリット
プログラムの入り口と出口が一つになり、流れを追いやすくなる可能性がある。
予期せぬ場所での強制終了を防げる。
デメリット
if文の入れ子が深くなり、コードが読みづらくなることがある。
フラグ変数など、管理すべき状態が増えて複雑になることがある。
今後の学習の指針
Javaの学習において、breakやcontinueは「適材適所」で使う道具です。包丁と同じで、正しく使えば便利ですが、振り回せば危険です。
まずは、以下のステップで学習を進めてみてください。
- 基本的なbreakとcontinueの動きをコードを書いて確認する。
- それらを使わずに同じ動きをするコードを書いてみる(今日やったことですね!)。
- どちらが読みやすいか、自分なりに比較してみる。
- 長くなった処理を「メソッド」に切り出して、returnでシンプルに書けないか検討する。
「使わないこと」自体が目的ではありません。「誰が見ても読みやすいコードを書くこと」が目的なのです。
迷ったときは、ぜひ周りのエンジニアや講師に「どっちが読みやすいですか?」と聞いてみてください。それが一番の成長への近道ですよ。
それでは、また次の記事でお会いしましょう。