制御構文

要約

  • 分岐:if / else if / elseswitch(式)を使い分ける
  • 反復:for / while / do-while / for-each を用途で選択
  • 制御:break / continue / returnラベルで外側ループ制御も可
  • 補助:三項演算子?:instanceofパターンマッチ、ガード節で可読性向上

1. 分岐:if / else if / else

int score = 72;
if (score >= 90) {
    System.out.println("A");
} else if (score >= 80) {
    System.out.println("B");
} else if (score >= 70) {
    System.out.println("C");
} else {
    System.out.println("D");
}

ポイント

  • 条件が短い順よりも意図が明確な順で(例:範囲の上から下へ)
  • 複雑化しそうなら 早期return(ガード節) を検討

2. 分岐:switch(従来/式)

2.1 従来のswitch(break必須)

String role = "USER";
switch (role) {
    case "ADMIN":
        authorizeAll();
        break;
    case "USER":
        authorizeLimited();
        break;
    default:
        deny();
}
  • breakを書き忘れるとフォールスルー

2.2 switch (Java 14+)

int n = 8;
String label = switch (n) {
    case 10, 9 -> "A";
    case 8     -> "B";
    case 7     -> "C";
    case 6     -> "D";
    default    -> "F";
};

複数文が必要ならyield

String msg = switch (role) {
    case "ADMIN" -> "all access";
    case "USER"  -> {
        logAccess(role);
        yield "limited";
    }
    default -> "denied";
};

ポイント:式は値を返すため、変数初期化に有効/break不要で安全

3. 反復:for / while / do-while / for-each

3.1 伝統的for

for (int i = 0; i < 10; i++) {
    process(i);
}
  • 添字が必要なときに適する

3.2 while

while (hasNext()) {
    handle(next());
}
  • 条件を先に評価。0回もあり得る

3.3 do-while

do {
    readOnce();
} while (needMore());
  • 本体を最低1回は実行

3.4 拡張for(for-each)

List<String> names = List.of("A","B","C");
for (String s : names) {
    System.out.println(s);
}
  • 要素列挙が目的なら最有力。インデックス不要で可読

4. ループ制御:break / continue と ラベル

// break/continue
for (int i = 0; i < 10; i++) {
    if (i == 5) continue; // 5をスキップ
    if (i == 8) break;    // 8でループ終了
}

// ラベル付き break(多重ループを一気に抜ける)
outer:
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 1 && j == 2) break outer; // outerループを抜ける
    }
}

注意:ラベル多用は可読性低下。関数分割フラグ変数回避を検討

5. 三項演算子(条件演算子)?:

int age = 20;
String category = (age >= 18) ? "adult" : "child";
  • 短い条件分岐に限定して使う(ネスト禁止)

6. instanceof パターンマッチ(Java 16+)

Object obj = "hello";
if (obj instanceof String s && s.length() > 3) {
    System.out.println(s.toUpperCase()); // 直接sが使える
}
  • instanceof後のキャスト不要で簡潔・安全

7. ガード節(早期return)でネスト削減

void register(User u) {
    if (u == null) return;                 // 早期リターン
    if (!u.isValid()) { log("invalid"); return; }
    save(u);
}
  • 「例外条件を先に排除」→ 本筋の処理が浅いネストで書ける

8. 実用サンプル(1ファイル)

import java.util.List;

public class ControlFlowSample {
    static String grade(int score) {
        // switch式で値を返す
        return switch (score / 10) {
            case 10, 9 -> "A";
            case 8 -> "B";
            case 7 -> "C";
            case 6 -> "D";
            default -> "F";
        };
    }

    static int findFirstEven(List<Integer> xs) {
        // for-each と 早期return
        for (int n : xs) {
            if (n % 2 == 0) return n;
        }
        return -1; // 見つからない場合
    }

    public static void main(String[] args) {
        System.out.println(grade(83)); // B

        outer:
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (i == 1 && j == 1) {
                    System.out.println("break outer");
                    break outer;
                }
            }
        }

        Object obj = "hi";
        if (obj instanceof String s && !s.isEmpty()) {
            System.out.println(s.repeat(2)); // hihi
        }
    }
}

ベストプラクティス要点

  • 分岐はswitch式で漏れを減らす(defaultで安全側)
  • 反復はfor-each優先、添字が必要な場合のみ従来for
  • 複雑な条件は意味のあるメソッド名に抽出(例:isEligible()
  • 早期returnでネストを浅く、ラベルの多用は避ける
  • 三項演算子は1行・単純条件まで(ネスト禁止)

次回は 基礎構文③ クラスとメソッド をご用意します。