1. 導入:なぜ今、continue文を見直すべきか
現場でコードレビューをしていると、ネストの深いif文が連なり、可読性が著しく低下しているケースによく遭遇します。特に複雑なビジネスロジックを扱う際、条件を満たさない場合に早期に次のループ処理へ移行させる「continue」の活用は、コードのフラット化を図るための非常に重要な手法です。本稿では、基本的な使い方から、Java 17以降のモダンな制御構造(sealed classesやswitch expressions)と組み合わせた、より「保守性の高い」制御フローの書き方を解説します。
2. 基礎知識:continue文とは
continue文は、ループ(for, while, do-while)の中で実行されると、そのループの残りの処理をスキップし、次の繰り返し処理へと制御を移す命令です。
重要なのは、continueを使うことでif-elseのネストを一段分減らせるという点です。「ガード節」のように条件を満たさないケースを先に処理することで、メインの処理がメソッドの左端に揃い、コードの意図が読み取りやすくなります。
3. 実装/解決策:ラベル付きcontinueとモダンな制御の融合
実務では、多重ループを制御するために「ラベル付きcontinue」を使用する場面もあります。また、近年ではswitch expressionsやsealed classesを用いた型網羅性の高いコードが推奨されています。これらとcontinueを組み合わせることで、堅牢なロジックを構築可能です。
4. サンプルプログラム
以下のコードは、sealedクラスで定義された複数の注文ステータスをループ処理し、特定の条件でスキップしつつ、複雑な制御を回避する例です。
// 注文状態を定義(Sealed Classesで網羅性を確保)
sealed interface OrderStatus permits Pending, Shipped, Cancelled {}
record Pending() implements OrderStatus {}
record Shipped() implements OrderStatus {}
record Cancelled() implements OrderStatus {}
public class OrderProcessor {
public void processOrders(List
outerLoop: // ラベルを設定
for (OrderStatus order : orders) {
// switch expressionsで処理を切り分け
boolean shouldSkip = switch (order) {
case Pending p -> false; // 処理対象
case Shipped s -> true; // 完了済みはスキップ対象
case Cancelled c -> true; // キャンセル済みもスキップ対象
};
// continueを使ってifのネストを回避
if (shouldSkip) {
System.out.println("スキップ対象です。次の注文へ進みます。");
continue;
}
// 本来のメイン処理(ネストが浅く保たれている)
System.out.println("注文処理を実行中: " + order.getClass().getSimpleName());
}
}
}
5. 応用・注意点:現場で陥りやすい罠
・ラベル付きcontinueの多用は禁物:
ラベル付きcontinueは便利ですが、多用すると処理の流れが追いにくくなり、スパゲッティコードの温床になります。基本的にはループのネストは2段階までに留め、それ以上深くなる場合はメソッドの抽出を検討してください。
・yieldとの混同に注意:
switch expressions内でyieldを使うと値が返りますが、continueはあくまでループ制御です。switchの中でcontinueを直接書くことはできません。サンプルコードのように、一度boolean変数などに判定結果を格納してからループ内でcontinueを呼ぶのが、Javaの言語仕様上クリーンな書き方です。
・可読性のための空行:
continueの直後には、必ず処理の区切りとなる空行を入れるか、条件分岐が明確であることを示すコメントを残すようにしましょう。これにより、後続のエンジニアが「なぜここで処理がスキップされるのか」を一目で理解できるようになります。

コメント