Javaの基本的な制御構造:条件分岐とループ

1. 条件分岐:条件に基づいてコードの実行パスを選択する

条件分岐は、異なる条件に基づいて異なるコードブロックを実行するために使用されます。Javaでは主に `if` 系列と `switch` 文が利用されます。

単純な if: 1つの条件を評価する

特徴: 1つの条件を評価し、条件が真であればコードブロックを実行します。

構文テンプレート:

if (ブール式) {
    // 条件が true の場合に実行されるコード
}

コード例:

int score = 85;
// スコアが合格点以上かどうかを確認
if (score >= 60) {
    System.out.println("試験に合格しました"); // 出力: 試験に合格しました
}

一般的な落とし穴: 大括弧 `{}` を省略すると、後続のステートメントが `if` の制御範囲内に含まれる可能性があり、論理エラーを引き起こすことがあります。

// エラー例: 大括弧を省略
if (score >= 60)
    System.out.println("合格");
    System.out.println("もっと頑張ろう"); // 条件に関係なく常に実行(ifの制御外)

正しい書き方: たとえ1行のコードであっても、大括弧を付けて読みやすさと安全性を高めることが推奨されます。

if-else: 2つの選択肢から1つを選ぶ

特徟能: 1つの条件を評価し、条件が真であれば `if` ブロックを、偽であれば `else` ブロックを実行します。

構文テンプレート:

if (ブール式) {
    // 条件が true の場合に実行
} else {
    // 条件が false の場合に実行
}

コード例:

int age = 17;
if (age >= 18) {
    System.out.println("成人です");
} else {
    System.out.println("未成年です"); // 出力: 未成年です
}

面接でのポイント: 三項演算子(`条件 ? 式1 : 式2`)は `if-else` の簡易版で、値を返します。

// 三項演算子を使用して上記の if-else と同じ処理を行う
String result = (age >= 18) ? "成人です" : "未成年です";
System.out.println(result); // 出力: 未成年です

注意: 三項演算子は、式1と式2の戻り値が互換性がある場合に使用でき、単純なロジックに適しています。複雑なロジックには `if-else` を使用することをお勧めします。

else if: 複数の条件を評価する

特徴: 複数の条件を順番に評価し、最初に真となる条件に対応するコードブロックを実行し、それ以降の評価を停止します。

構文テンプレート:

if (条件1) {
    // 条件1が真の場合に実行
} else if (条件2) {
    // 条件1が偽で条件2が真の場合に実行
} else if (条件3) {
    // 前の2つの条件が偽で条件3が真の場合に実行
} else {
    // すべての条件が偽の場合に実行(オプション)
}

コード例:

int score = 85;
if (score >= 90) {
    System.out.println("優秀");
} else if (score >= 80) {
    System.out.println("良好"); // 出力: 良好(最初の真の条件が見つかった時点で終了)
} else if (score >= 60) {
    System.out.println("合格");
} else {
    System.out.println("不合格");
}

一般的な落とし穴: Javaには `elseif` というキーワードは存在せず、`else if` と書く必要があります。

// エラー例: コンパイルエラー
if (a > 10) {
} elseif (a > 5) { // 正しくは else if
}

switch: 複数の値をマッチングする

特徴: 変数の値に基づいて複数の定数をマッチングします。離散値(列挙型、整数、文字列など)の条件判断に適しています。

構文テンプレート(基本版):

switch (変数) {
    case 定数1:
        // 変数が定数1と一致する場合に実行
        break; // switch から抜ける
    case 定数2:
        // 変数が定数2と一致する場合に実行
        break;
    default:
        // どの定数とも一致しない場合に実行(オプション)
}

サポートされる変数の型:

  • 基本型: `byte`, `short`, `int`, `char`
  • 参照型: `String`(JDK 7+)、列挙型(`enum`)

コード例1: 基本的な使用法(整数のマッチング):

int week = 3;
switch (week) {
    case 1:
        System.out.println("月曜日");
        break;
    case 2:
        System.out.println("火曜日");
        break;
    case 3:
        System.out.println("水曜日"); // 出力: 水曜日
        break;
    default:
        System.out.println("他の曜日");
}

コード例2: 文字列のマッチング(JDK 7+):

String day = "Tuesday";
switch (day) {
    case "Monday":
        System.out.println("月曜日");
        break;
    case "Tuesday":
        System.out.println("火曜日"); // 出力: 火曜日
        break;
    default:
        System.out.println("不明");
}

一般的な落とし穴:

  1. `break` を忘れると、次の `case` のコードも実行されます。
  2. JDK 14+ では `yield` を使用して値を返すことができます。
int month = 4;
String season = switch (month) {
    case 3, 4, 5 -> { // 複数の値をカンマ区切りで指定
        yield "春"; // 値を返す
    }
    case 6, 7, 8 -> "夏"; // 単一行では yield と大括弧を省略可能
    default -> "その他の季節";
};
System.out.println(season); // 出力: 春

2. ループ構造: コードブロックを繰り返し実行する

ループ構造は、特定のコードブロックを繰り返し実行するために使用されます。Java には `while`, `do-while`, `for` の3種類のループがあります。

while: 条件を評価してから実行する

特徴: 条件を評価し、条件が真であればループ体を実行します。

構文テンプレート:

while (ループ条件) {
    // 条件が真の場合に実行されるループ体
}

適用場面: ループ回数が不確定で、終了条件がわかっている場合(ファイルの読み込み、ユーザー入力の待機など)。

コード例: ユーザー入力を "exit" まで読み込む

Scanner scanner = new Scanner(System.in);
String input;
// ループ条件: 入力が "exit" でない
while (!"exit".equals(input = scanner.nextLine())) {
    System.out.println("あなたは " + input + " を入力しました");
}
System.out.println("プログラム終了");

do-while: 実行してから条件を評価する

特徴: 最初に1回ループ体を実行し、その後条件を評価します。

構文テンプレート:

do {
    // ループ体: 少なくとも1回実行
} while (ループ条件); // 注意: 末尾にセミコロンが必要

適用場面: 最初に1回実行する必要がある場合(メニュー駆動、パスワード再試行、初期化チェックなど)。

コード例: パスワード再試行機能

Scanner scanner = new Scanner(System.in);
String password;
do {
    System.out.print("パスワードを入力してください: ");
    password = scanner.nextLine();
} while (!"123456".equals(password)); // パスワードが誤った場合は再試行
System.out.println("パスワードが正解です");

for: 構造化されたカウントループ

`for` ループは最も柔軟なループ構造であり、カウントループ、イテレーターループ、強化された `for` ループをサポートします。

基本的な for ループ(カウントループ):

構文テンプレート:

for (①初期化; ②ループ条件; ③反復操作) {
    ④ループ体
}

コード例: 1~5の数字を出力する

for (int i = 1; i <= 5; i++) { // i=1で初期化; 条件i<=5; 各ループ後にi+1
    System.out.println(i); // 出力: 1 2 3 4 5
}

強化された for ループ(foreach, JDK 5+):

特徴: 配列やコレクションの反復を簡素化し、インデックスの管理なしに要素を直接取得します。

構文テンプレート:

for (要素型 変数名 : 配列/コレクション) {
    // ループ体: 変数名は現在の要素を表す
}

コード例: 配列の反復

int[] nums = {10, 20, 30};
for (int num : nums) { // 配列内の各要素を反復
    System.out.println(num); // 出力: 10 20 30
}

一般的な落とし穴: 強化された for ループでは、要素自体やコレクションの構造を変更することはできません。

// エラー例: 基本型の要素を変更しようとする(無効)
for (int num : nums) {
    num = 0; // 一時変数のみ変更され、元の配列は変更されない
}
System.out.println(nums[0]); // 依然として 10

イテレーターループ(コレクションの反復):

イテレーター(`Iterator`)を使用してコレクションを反復し、ループ内で安全に要素を削除できます。

コード例:

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");

Iterator<String> it = list.iterator();
while (it.hasNext()) { // 次の要素があるか確認
    String elem = it.next(); // 次の要素を取得
    System.out.println(elem);
    if ("A".equals(elem)) {
        it.remove(); // 現在の要素を安全に削除
    }
}

for ループの一般的な落とし穴:

  1. ループ条件に代入式を使用すると無限ループになる可能性があります。
  2. 強化された for ループでコレクションを変更すると `ConcurrentModificationException` が発生します。

3. 制御フローを変更するキーワード: `break`, `continue`, `return`

これらのキーワードは、ループや条件分岐内で実行順序を変更するために使用されます。

break: 現在のループまたは switch 文を強制終了する

機能: 現在のループ(`while`, `for`, `do-while`)または `switch` 文を強制終了します。

基本的な使用法: 現在のループを終了する

for (int i = 0; i < 10; i++) {
    if (i == 3) {
        break; // i=3 のとき、ループを終了
    }
    System.out.println(i); // 出力: 0 1 2
}

ラベル付き break: 外側のループを終了する: ラベル(`ラベル名:`)を使用して外側のループを終了することができます。

// ラベル out で外側のループをマーク
out: for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 1 && j == 1) {
            break out; // 外側のループを終了
        }
        System.out.println(i + "," + j);
    }
}
// 出力: 0,0  0,1  0,2  1,0

continue: 今回のループの残りをスキップする

機能: 現在のループの残りの部分をスキップし、次のループの判定に進みます。

基本的な使用法: 今回のループの残りをスキップする

for (int i = 0; i < 5; i++) {
    if (i % 2 == 0) { // i が偶数の場合
        continue; // 今回のループの残りをスキップ
    }
    System.out.println(i); // 出力: 1 3
}

ラベル付き continue: 外側のループの次の反復に進む: 外側のループの次の反復に進みます。

out: for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (j == 1) {
            continue out; // 外側のループの次の反復に進む(i+1)
        }
        System.out.println(i + "," + j);
    }
}
// 出力: 0,0  1,0  2,0

return: メソッドの終了

機能: 現在のメソッドの実行を即座に終了し、メソッド呼び出し元に戻ります。メソッドに戻り値がある場合は、その値を返します。

コード例1: 戻り値がないメソッド:

public static void printNum(int num) {
    if (num < 0) {
        return; // メソッドを終了
    }
    System.out.println(num);
}

// 呼び出し
printNum(-1); // 出力なし(メソッドが早期終了)

コード例2: 戻り値があるメソッド:

public static int add(int a, int b) {
    return a + b; // 計算結果を返し、メソッドを終了
}

特殊な場面: `main` メソッドで `return` を使用すると、プログラムが終了します。

public static void main(String[] args) {
    System.out.println("開始");
    return; // プログラムを終了
    // 以下のコードは実行されない
    System.out.println("終了");
}

タグ: Java 条件分岐 ループ 制御構造 if

9月27日 11:53 投稿