タイトル: 制御構文
SEOタイトル: Java 制御構文完全ガイド (if/switch/for/while)
| この記事の要点 |
|
if / else / else if
int score = 75;
if (score >= 90) {
System.out.println("A");
} else if (score >= 70) {
System.out.println("B"); // ← ここに入る
} else if (score >= 50) {
System.out.println("C");
} else {
System.out.println("F");
}
// 単一行は { } 省略可能だがバグの温床なので推奨しない
if (x > 0) System.out.println("positive");
三項演算子
// 条件 ? 真の値 : 偽の値
int age = 20;
String label = (age >= 20) ? "大人" : "未成年";
// ネストは可能だが読みにくい
String grade = score >= 90 ? "A"
: score >= 70 ? "B"
: score >= 50 ? "C" : "F";
// ★ null チェック
String name = (user != null) ? user.getName() : "(unknown)";
// Java 8+ は Optional 推奨
String name2 = Optional.ofNullable(user).map(User::getName).orElse("(unknown)");
switch (古い文と新しい式)
古い switch 文 (Java 13 以前)
int day = 3;
String name;
switch (day) {
case 1:
name = "月";
break; // ★ break 忘れると次に流れる (fall-through)
case 2:
name = "火";
break;
case 3:
case 4:
name = "水or木"; // フォールスルーで複数 case
break;
default:
name = "?";
break;
}
新しい switch 式 (Java 14+)
// 矢印構文 -> はフォールスルーしない (break 不要)
String name = switch (day) {
case 1 -> "月";
case 2 -> "火";
case 3, 4 -> "水or木"; // ★ カンマで複数 case まとめ
default -> "?";
};
// 複数行は yield
String label = switch (day) {
case 1, 2, 3, 4, 5 -> "平日";
case 6, 7 -> {
log.info("休日です");
yield "休日"; // ★ switch 式の戻り値
}
default -> throw new IllegalArgumentException();
};
Pattern Matching (Java 21+)
// 型と値による分岐
sealed interface Shape permits Circle, Square {}
record Circle(double r) implements Shape {}
record Square(double s) implements Shape {}
double area = switch (shape) {
case Circle c -> Math.PI * c.r() * c.r();
case Square sq -> sq.s() * sq.s();
};
// ガード節 (when)
String size = switch (n) {
case Integer i when i < 0 -> "negative";
case Integer i when i == 0 -> "zero";
case Integer i -> "positive";
};
for 文
// 初期化; 条件; 更新
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// 2 つ並列
for (int i = 0, j = 10; i < j; i++, j--) {
System.out.println(i + "," + j);
}
// 無限ループ
for (;;) {
if (done) break;
}
// 拡張 for (for-each)
for (String name : names) {
System.out.println(name);
}
while と do-while の使い分け
| 構文 | 条件チェック | 最低実行回数 |
|---|---|---|
while | ループ前 | 0 回 |
do-while | ループ後 | 1 回 |
// while: 条件が最初から false なら 1 度も実行されない
int i = 10;
while (i < 5) {
System.out.println(i); // ★ 表示されない
}
// do-while: 必ず 1 回は実行
int j = 10;
do {
System.out.println(j); // ★ 10 を 1 回表示
} while (j < 5);
// 典型例: ユーザー入力ループ
String input;
do {
System.out.print("Enter (q to quit): ");
input = scanner.nextLine();
process(input);
} while (!input.equals("q"));
break / continue / ラベル付き
for (int i = 0; i < 10; i++) {
if (i == 3) continue; // この回をスキップ → 0,1,2,4,5,6,7,8,9
if (i == 7) break; // ループ脱出 → 0,1,2,4,5,6
System.out.println(i);
}
// ラベル付き break で多重ループ一気に脱出
outer:
for (int[] row : matrix) {
for (int n : row) {
if (n == -1) break outer; // ★ 外側ループも脱出
}
}
// ラベル付き continue で外側ループの次イテレーション
outer:
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (skip[i][j]) continue outer; // 外側ループの次へ
}
}
try-with-resources (Java 7+)
AutoCloseable を実装したリソースを自動で閉じます。finally で close() を呼ぶ昔の書き方より安全。
// 自動クローズ
try (
FileReader fr = new FileReader("a.txt");
BufferedReader br = new BufferedReader(fr)
) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} // ★ ここで br → fr の順に自動 close
// 例外も自動でログ
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) { ... }
}
null チェックの定番
// クラシック
if (user != null && user.getName() != null) {
System.out.println(user.getName().length());
}
// Java 8+ Optional
Optional.ofNullable(user)
.map(User::getName)
.ifPresent(n -> System.out.println(n.length()));
// Objects ユーティリティ
String name = Objects.requireNonNullElse(user.getName(), "(unknown)");
// Objects.requireNonNull (ガード節)
public void setUser(User u) {
this.user = Objects.requireNonNull(u, "user must not be null");
}
例外による制御
try {
int n = Integer.parseInt(input);
} catch (NumberFormatException e) {
System.err.println("not a number: " + input);
} catch (Exception e) {
System.err.println("other: " + e);
} finally {
System.out.println("always");
}
// マルチキャッチ (Java 7+)
try {
...
} catch (IOException | SQLException e) {
log.error(e);
}
FAQ
Q: switch と if/else どちらを使う?
A: 比較対象が同じ変数で 3 つ以上の値で分岐するなら switch。範囲比較 (x > 0) は if。Java 14+ の switch 式は記述量が少なく推奨。
Q: 古い break 付き switch はもう不要?
A: Java 14+ は新しい矢印構文 (->) を強く推奨。fall-through バグの温床を排除できます。
Q: while(true) と for(;;) はどちらが好まれる?
A: 機能的に同じ。可読性は while (true)、コンパイラ警告を避けたいなら for (;;) という流派もある。