はじめに#
プログラミングにおいて、データを計算したり、条件に応じて処理を分岐させたり、同じ処理を繰り返し実行したりする機能は不可欠です。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 + " は奇数");
}
}
|
可読性を保つためのヒント#
ネストが深くなるとコードの可読性が低下します。以下のテクニックを活用してください。
- 早期リターン(Early Return): 条件を満たさない場合に早めに処理を終了する
- メソッドへの分割: 複雑なロジックは別メソッドに切り出す
- 適切なコメント: 複雑な条件には意図を説明するコメントを付ける
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: ループ制御
- ネストした制御構文: 可読性を保つテクニック
これらの構文を使いこなすことで、条件に応じた柔軟な処理を実装できるようになります。次のステップとして、配列や文字列の操作を学ぶことで、より実践的なプログラムを作成できるようになります。
参考リンク#