はじめに

プログラミングにおいて、データを計算したり、条件に応じて処理を分岐させたり、同じ処理を繰り返し実行したりする機能は不可欠です。Javaでは演算子制御構文を使用して、これらの処理を実現します。

この記事では、Javaの基本的な演算子から始まり、if-else文による条件分岐、Java 14以降で正式導入されたswitch式、そしてfor/whileループまで、段階的に解説します。これらをマスターすることで、プログラムの流れを自在に制御できるようになります。

算術演算子と代入演算子

算術演算子は数値の計算に使用し、代入演算子は変数に値を格納するために使用します。

算術演算子

Javaで使用できる基本的な算術演算子は以下の通りです。

演算子 説明 結果
+ 加算 5 + 3 8
- 減算 5 - 3 2
* 乗算 5 * 3 15
/ 除算 5 / 3 1(整数同士の場合)
% 剰余(余り) 5 % 3 2
1
2
3
4
5
6
7
8
int a = 10;
int b = 3;

System.out.println(a + b);  // 13
System.out.println(a - b);  // 7
System.out.println(a * b);  // 30
System.out.println(a / b);  // 3(整数の除算は小数点以下が切り捨て)
System.out.println(a % b);  // 1

整数同士の除算では結果も整数になり、小数点以下は切り捨てられます。小数を含む結果が必要な場合は、少なくとも一方をdouble型にキャストしてください。

1
2
3
4
int x = 5;
int y = 2;
System.out.println(x / y);           // 2(整数の除算)
System.out.println((double) x / y);  // 2.5(キャストにより小数結果を取得)

インクリメント演算子とデクリメント演算子

変数の値を1増やす(インクリメント)または1減らす(デクリメント)演算子です。前置と後置で挙動が異なります。

演算子 説明
++ インクリメント i++または++i
-- デクリメント i--または--i
1
2
3
4
5
6
7
8
9
int i = 5;

// 後置:現在の値を使用してから1増加
System.out.println(i++);  // 5を出力後、iは6になる
System.out.println(i);    // 6

// 前置:1増加してから値を使用
System.out.println(++i);  // iを7にしてから出力
System.out.println(i);    // 7

代入演算子

代入演算子は変数に値を代入するために使用します。基本の=に加え、複合代入演算子も用意されています。

演算子 説明 同等の式
= 代入 a = 5 -
+= 加算代入 a += 3 a = a + 3
-= 減算代入 a -= 3 a = a - 3
*= 乗算代入 a *= 3 a = a * 3
/= 除算代入 a /= 3 a = a / 3
%= 剰余代入 a %= 3 a = a % 3
1
2
3
4
5
6
int score = 100;
score += 10;  // score = score + 10; と同じ
System.out.println(score);  // 110

score -= 20;  // score = score - 20; と同じ
System.out.println(score);  // 90

比較演算子と論理演算子

条件分岐やループの条件判定に使用する演算子です。

比較演算子

2つの値を比較し、結果をboolean型(trueまたはfalse)で返します。

演算子 説明 結果
== 等しい 5 == 5 true
!= 等しくない 5 != 3 true
> より大きい 5 > 3 true
< より小さい 5 < 3 false
>= 以上 5 >= 5 true
<= 以下 5 <= 3 false
1
2
3
4
5
6
7
8
int age = 20;

System.out.println(age == 20);  // true
System.out.println(age != 18);  // true
System.out.println(age > 18);   // true
System.out.println(age < 30);   // true
System.out.println(age >= 20);  // true
System.out.println(age <= 25);  // true

オブジェクトの比較では==は参照(メモリアドレス)を比較します。内容を比較する場合はequals()メソッドを使用してください。この違いは前回の記事「Javaの変数とデータ型」でも解説しています。

論理演算子

複数の条件を組み合わせて判定するために使用します。

演算子 説明 結果
&& 論理AND(両方true) true && false false
|| 論理OR(どちらかtrue) true || false true
! 論理NOT(否定) !true false
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
int age = 25;
boolean hasLicense = true;

// 20歳以上かつ免許を持っている場合
if (age >= 20 && hasLicense) {
    System.out.println("運転できます");
}

// 学生または65歳以上の場合
int studentAge = 19;
boolean isStudent = true;
if (isStudent || studentAge >= 65) {
    System.out.println("割引対象です");
}

// 否定の例
boolean isRaining = false;
if (!isRaining) {
    System.out.println("傘は不要です");
}

短絡評価

&&||は**短絡評価(ショートサーキット評価)**を行います。これは、結果が確定した時点で残りの条件を評価しない仕組みです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int x = 0;

// &&の場合:左辺がfalseなら右辺は評価されない
if (x != 0 && 10 / x > 1) {
    System.out.println("条件成立");
}
// x が 0 でも、10 / x は評価されないためエラーにならない

// ||の場合:左辺がtrueなら右辺は評価されない
if (x == 0 || 10 / x > 1) {
    System.out.println("条件成立");  // 出力される
}

短絡評価を活用することで、nullチェックと処理を1つの条件式にまとめられます。

1
2
3
4
5
6
String name = null;

// nameがnullの場合、右辺は評価されないためNullPointerExceptionを防げる
if (name != null && name.length() > 0) {
    System.out.println("名前:" + name);
}

if-else文による条件分岐

条件に応じて処理を分岐させる最も基本的な構文です。

基本的なif文

1
2
3
4
5
int score = 85;

if (score >= 80) {
    System.out.println("合格です");
}

if-else文

条件がfalseの場合に実行する処理を指定できます。

1
2
3
4
5
6
7
int score = 65;

if (score >= 70) {
    System.out.println("合格です");
} else {
    System.out.println("不合格です");
}

if-else if-else文

複数の条件を順番に判定する場合に使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int score = 85;

if (score >= 90) {
    System.out.println("評価:A");
} else if (score >= 80) {
    System.out.println("評価:B");
} else if (score >= 70) {
    System.out.println("評価:C");
} else if (score >= 60) {
    System.out.println("評価:D");
} else {
    System.out.println("評価:F");
}
// 出力:評価:B

条件は上から順番に評価され、最初にtrueとなった条件のブロックのみが実行されます。

三項演算子

単純な条件分岐は三項演算子(条件演算子)でシンプルに記述できます。

1
2
3
int age = 20;
String status = (age >= 18) ? "成人" : "未成年";
System.out.println(status);  // 成人

構文は 条件 ? true時の値 : false時の値 です。可読性を損なわない範囲で活用してください。

switch式(Java 14以降のモダンな書き方)

switchは複数の値に対する分岐処理を記述する構文です。Java 14(JEP 361)でswitch式が正式に導入され、より簡潔で安全な記述が可能になりました。

従来のswitch文

従来のswitch文はbreakを忘れるとフォールスルー(次のcaseに処理が流れる)が発生し、バグの原因になりがちでした。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 従来のswitch文(非推奨)
int day = 3;
String dayName;

switch (day) {
    case 1:
        dayName = "月曜日";
        break;
    case 2:
        dayName = "火曜日";
        break;
    case 3:
        dayName = "水曜日";
        break;
    case 4:
        dayName = "木曜日";
        break;
    case 5:
        dayName = "金曜日";
        break;
    case 6:
        dayName = "土曜日";
        break;
    case 7:
        dayName = "日曜日";
        break;
    default:
        dayName = "不正な値";
        break;
}
System.out.println(dayName);

モダンなswitch式(アロー構文)

Java 14以降では、アロー構文(->)を使用したswitch式が推奨されます。breakが不要でフォールスルーが発生せず、値を直接返すことができます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int day = 3;

String dayName = switch (day) {
    case 1 -> "月曜日";
    case 2 -> "火曜日";
    case 3 -> "水曜日";
    case 4 -> "木曜日";
    case 5 -> "金曜日";
    case 6 -> "土曜日";
    case 7 -> "日曜日";
    default -> "不正な値";
};

System.out.println(dayName);  // 水曜日

複数のラベルをまとめる

同じ処理を複数の値に適用する場合、カンマで区切って記述できます。

1
2
3
4
5
6
7
8
9
int day = 6;

String dayType = switch (day) {
    case 1, 2, 3, 4, 5 -> "平日";
    case 6, 7 -> "週末";
    default -> "不正な値";
};

System.out.println(dayType);  // 週末

ブロック構文とyield

複数の処理を実行して値を返す場合は、ブロック({})とyieldを使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int month = 2;

int days = switch (month) {
    case 1, 3, 5, 7, 8, 10, 12 -> 31;
    case 4, 6, 9, 11 -> 30;
    case 2 -> {
        // うるう年の判定など複雑な処理も可能
        System.out.println("2月の日数を計算中...");
        yield 28;  // yieldで値を返す
    }
    default -> throw new IllegalArgumentException("不正な月: " + month);
};

System.out.println(month + "月は" + days + "日あります");

switch式の網羅性

switch式では、すべての可能な値をカバーする必要があります(網羅性)。enumを使用する場合、すべての列挙値をカバーすればdefaultは不要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
enum Season { SPRING, SUMMER, AUTUMN, WINTER }

Season season = Season.SUMMER;

String activity = switch (season) {
    case SPRING -> "花見";
    case SUMMER -> "海水浴";
    case AUTUMN -> "紅葉狩り";
    case WINTER -> "スキー";
    // enumの全値をカバーしているのでdefaultは不要
};

System.out.println(activity);  // 海水浴

switch式とswitch文の使い分け

特徴 switch式(推奨) 従来のswitch文
値を返せる 可能 不可
break必須 不要 必要
フォールスルー 発生しない 発生する可能性あり
網羅性チェック コンパイラが検証 なし

新規開発では、switch式(アロー構文)の使用を推奨します。

forループとwhileループ

同じ処理を繰り返し実行するためのループ構文です。

forループ

繰り返し回数が明確な場合に使用します。

1
2
3
4
5
// 基本構文:for (初期化; 条件; 更新) { 処理 }
for (int i = 0; i < 5; i++) {
    System.out.println("カウント: " + i);
}
// 出力:0, 1, 2, 3, 4

forループの各部分の役割は以下の通りです。

flowchart TD
    A[初期化: int i = 0] --> B{条件判定: i < 5}
    B -->|true| C[ループ本体を実行]
    C --> D[更新: i++]
    D --> B
    B -->|false| E[ループ終了]

whileループ

条件がtrueの間、繰り返し処理を実行します。繰り返し回数が不明な場合に適しています。

1
2
3
4
5
6
int count = 0;

while (count < 5) {
    System.out.println("カウント: " + count);
    count++;
}

条件判定はループ本体の実行前に行われます。最初から条件がfalseの場合、一度も実行されません。

1
2
3
4
5
6
int x = 10;

while (x < 5) {
    System.out.println("この行は実行されません");
    x++;
}

do-whileループ

条件判定をループの最後に行うため、最低1回は必ず実行されます。

1
2
3
4
5
6
int count = 0;

do {
    System.out.println("カウント: " + count);
    count++;
} while (count < 5);

ユーザー入力の検証など、「少なくとも1回は処理を実行したい」場合に適しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import java.util.Scanner;

Scanner scanner = new Scanner(System.in);
int input;

do {
    System.out.print("1から10の数字を入力してください: ");
    input = scanner.nextInt();
} while (input < 1 || input > 10);

System.out.println("入力された値: " + input);

ループの使い分け

ループ 使用シーン
for 繰り返し回数が明確な場合
while 条件が満たされる間繰り返す場合
do-while 最低1回は実行したい場合

拡張for文(for-each)

配列やコレクションの全要素を順番に処理する場合、拡張for文(for-each文)を使用すると簡潔に記述できます。

配列での使用例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int[] numbers = {1, 2, 3, 4, 5};

// 従来のforループ
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

// 拡張for文(推奨)
for (int number : numbers) {
    System.out.println(number);
}

拡張for文の構文は for (型 変数名 : 配列またはコレクション) です。

コレクションでの使用例

1
2
3
4
5
6
7
import java.util.List;

List<String> fruits = List.of("りんご", "みかん", "ぶどう");

for (String fruit : fruits) {
    System.out.println(fruit);
}

拡張for文の注意点

拡張for文にはいくつかの制限があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
int[] numbers = {1, 2, 3, 4, 5};

// インデックスにアクセスできない
for (int number : numbers) {
    // 何番目の要素かを知る方法がない
    System.out.println(number);
}

// 要素の変更はできない(元の配列には影響しない)
for (int number : numbers) {
    number = number * 2;  // 元の配列は変更されない
}

// 逆順やスキップはできない
// → 従来のforループを使用する

インデックスが必要な場合や、要素の削除・変更が必要な場合は、従来のforループを使用してください。

breakとcontinueの使い方

ループの制御を細かく行うための文です。

break文

ループを途中で終了します。

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

continue文

現在のイテレーションをスキップし、次のイテレーションに進みます。

1
2
3
4
5
6
7
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
        continue;  // 偶数の場合はスキップ
    }
    System.out.println(i);
}
// 出力:1, 3, 5, 7, 9(奇数のみ)

ラベル付きbreak/continue

ネストしたループで外側のループを制御する場合、ラベルを使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
outer:  // ラベルを定義
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 1 && j == 1) {
            break outer;  // 外側のループを終了
        }
        System.out.println("i=" + i + ", j=" + j);
    }
}
// 出力:
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0

ラベルを使用せずにbreakを使うと、最も内側のループのみが終了します。

ネストした制御構文の書き方

実際のプログラムでは、条件分岐やループを組み合わせて使用することが多くあります。

条件分岐のネスト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int age = 25;
boolean hasLicense = true;

if (age >= 18) {
    if (hasLicense) {
        System.out.println("運転できます");
    } else {
        System.out.println("免許を取得してください");
    }
} else {
    System.out.println("18歳になったら免許を取得できます");
}

ネストが深くなる場合は、論理演算子を使用して条件をまとめるか、早期リターン(early return)パターンを検討してください。

1
2
3
4
// 論理演算子でまとめる
if (age >= 18 && hasLicense) {
    System.out.println("運転できます");
}

ループのネスト

二重ループは、2次元配列の処理や組み合わせの列挙などに使用します。

1
2
3
4
5
6
7
// 九九の表を出力
for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
        System.out.printf("%3d", i * j);
    }
    System.out.println();
}

ループ内での条件分岐

1
2
3
4
5
6
7
8
9
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

for (int number : numbers) {
    if (number % 2 == 0) {
        System.out.println(number + " は偶数");
    } else {
        System.out.println(number + " は奇数");
    }
}

可読性を保つためのヒント

ネストが深くなるとコードの可読性が低下します。以下のテクニックを活用してください。

  1. 早期リターン(Early Return): 条件を満たさない場合に早めに処理を終了する
  2. メソッドへの分割: 複雑なロジックは別メソッドに切り出す
  3. 適切なコメント: 複雑な条件には意図を説明するコメントを付ける
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 早期リターンの例
public void processUser(User user) {
    if (user == null) {
        return;  // nullの場合は早期リターン
    }
    
    if (!user.isActive()) {
        return;  // 非アクティブの場合も早期リターン
    }
    
    // メイン処理(ネストが浅くなる)
    System.out.println("ユーザー処理: " + user.getName());
}

まとめ

この記事では、Javaの演算子と制御構文について解説しました。

  • 算術演算子: 四則演算と剰余、インクリメント/デクリメント
  • 比較演算子・論理演算子: 条件判定と短絡評価
  • if-else文: 基本的な条件分岐
  • switch式: Java 14以降のモダンな書き方(アロー構文とyield
  • forループ/whileループ: 繰り返し処理
  • 拡張for文: 配列やコレクションの簡潔な処理
  • break/continue: ループ制御
  • ネストした制御構文: 可読性を保つテクニック

これらの構文を使いこなすことで、条件に応じた柔軟な処理を実装できるようになります。次のステップとして、配列や文字列の操作を学ぶことで、より実践的なプログラムを作成できるようになります。

参考リンク