【Java学習|豆知識】Javaのif文を使いこなす!制御フローの基本と応用テクニック

皆さん、こんにちは!Javaエンジニアの皆さんは、日々複雑なコードと格闘されていることと思います。今回は、どんなプログラムでも必ずと言っていいほどお世話になる「if文」について、その基本からちょっとした応用、そして現場で役立つ注意点まで、豆知識として深掘りしていきましょう。

なぜif文が重要なのか?

if文は、プログラムの実行パスを条件によって分岐させるための基本的な制御構造です。「もしこの条件が満たされたら、この処理を実行する。そうでなければ、別の処理を実行する」といった、私たちの日常的な判断と同じようなロジックをコンピュータに指示するために不可欠な機能です。if文を理解し、適切に使いこなすことは、エラーを防ぎ、より効率的で読みやすいコードを書くための第一歩となります。

if文の基礎知識

if文は、指定された条件式が `true`(真)である場合に、その直後のブロック内のコードを実行します。条件式が `false`(偽)の場合は、そのブロックはスキップされます。

  • if文: 基本的な形です。

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

  • if-else文: 条件式が `true` の場合はifブロックが実行され、`false` の場合はelseブロックが実行されます。

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

  • if-else if-else文: 複数の条件を順番に評価したい場合に使用します。

if (条件式1) {
// 条件式1がtrueの場合に実行されるコード
} else if (条件式2) {
// 条件式1がfalseで、条件式2がtrueの場合に実行されるコード
} else {
// 上記のどの条件式もfalseの場合に実行されるコード
}

switch文とswitch式(Java 14以降)

Java 14からは、switch文が「switch式」として進化し、より簡潔で強力になりました。従来のswitch文は文でしたが、switch式は値を返す式として機能します。

従来のswitch文

int day = 3;
String dayName;
switch (day) {
case 1:
dayName = “Monday”;
break;
case 2:
dayName = “Tuesday”;
break;
case 3:
dayName = “Wednesday”;
break;
default:
dayName = “Unknown”;
}
System.out.println(dayName); // Wednesday

switch式 (Java 14以降)
switch式では、`->` 演算子と `yield` キーワード(または直接値を返す)を使って、より簡潔に記述できます。

int day = 3;
String dayName = switch (day) {
case 1 -> “Monday”;
case 2 -> “Tuesday”;
case 3 -> “Wednesday”;
default -> “Unknown”;
};
System.out.println(dayName); // Wednesday

switch式は、`yield` キーワードを使うことで、ブロックを持つこともできます。

int day = 3;
String dayName = switch (day) {
case 1 -> { yield “Monday”; }
case 2 -> { yield “Tuesday”; }
case 3 -> { yield “Wednesday”; }
default -> { yield “Unknown”; }
};
System.out.println(dayName); // Wednesday

sealed classes (Java 17以降)

sealed classes(密封クラス)は、特定のクラスだけがそのクラスを継承または実装することを許可する機能です。これは、switch式と組み合わせることで、網羅的なチェックをコンパイル時に保証するために非常に強力です。

例えば、`Shape` という sealed class を定義し、`Circle` と `Rectangle` のみ継承を許可するとします。

// Shape.java
public sealed interface Shape permits Circle, Rectangle {
double area();
}

// Circle.java
public final class Circle implements Shape {
private final double radius;

public Circle(double radius) { this.radius = radius; }

@Override
public double area() {
return Math.PI radius radius;
}
}

// Rectangle.java
public final class Rectangle implements Shape {
private final double width;
private final double height;

public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}

@Override
public double area() {
return width height;
}
}

これをswitch式で処理すると、すべての可能な型(`Circle` と `Rectangle`)を網羅しているかどうかがコンパイル時にチェックされます。

public class ShapeCalculator {
public double calculateArea(Shape shape) {
return switch (shape) {
case Circle c -> c.area();
case Rectangle r -> r.area();
// default が不要になる。もし新しいShape派生クラスが追加されたらコンパイルエラーになる。
};
}
}

sealed classes と switch式を組み合わせることで、コードの安全性と保守性を大幅に向上させることができます。

サンプルプログラム

ここでは、if-else if-else文と、Java 14以降のswitch式を使った例を示します。

public class FlowControlDemo {

public static void main(String[] args) {
int score = 75;
String grade;

// — if-else if-else文による成績判定 —
System.out.println(“— if-else if-else文 —“);
if (score >= 90) {
grade = “A”; // 90点以上ならA
} else if (score >= 80) {
grade = “B”; // 80点以上90点未満ならB
} else if (score >= 70) {
grade = “C”; // 70点以上80点未満ならC
} else if (score >= 60) {
grade = “D”; // 60点以上70点未満ならD
} else {
grade = “F”; // 60点未満ならF
}
System.out.println(“成績 (if-else if-else): ” + grade); // 成績 (if-else if-else): C

// — switch式による成績判定 (Java 14以降) —
System.out.println(“\n— switch式 —“);
// switch式は値を返すため、直接変数に代入できる
grade = switch (score / 10) { // 10で割って、上位の桁で判定
case 10, 9 -> “A”; // 100点、90点台
case 8 -> “B”; // 80点台
case 7 -> “C”; // 70点台
case 6 -> “D”; // 60点台
default -> “F”; // それ以外 (0点~59点)
};
System.out.println(“成績 (switch式): ” + grade); // 成績 (switch式): C

// — switch式でyieldを使う例 —
System.out.println(“\n— switch式 with yield —“);
String feedback;
int attendance = 80; // 出席率

feedback = switch (attendance) {
case 100 -> { // 100%の場合
System.out.println(“素晴らしい出席率です!”);
yield “Excellent”; // yieldで値を返す
}
case 90, 95 -> { // 90%または95%の場合
System.out.println(“良い出席率です。”);
yield “Good”;
}
case 80, 85 -> { // 80%または85%の場合
System.out.println(“まずまずの出席率です。”);
yield “Fair”;
}
default -> { // それ以外の場合
System.out.println(“出席率に注意が必要です。”);
yield “Needs Improvement”;
}
};
System.out.println(“フィードバック: ” + feedback);
// 出力例:
// まずまずの出席率です。
// フィードバック: Fair
}
}

応用・注意点

  • ネストしたif文: if文の中にさらにif文を入れることも可能ですが、複雑になりすぎると可読性が低下します。可能な限り、ロジックをメソッドに切り出すなどの工夫をしましょう。
  • 条件式の優先順位: `&&` (AND) は `||` (OR) よりも優先順位が高いです。`()` を使って意図を明確にすると良いでしょう。
  • nullチェック: オブジェクトを扱う場合、`null` の可能性があります。`if (object != null)` のようなチェックを忘れると `NullPointerException` が発生します。
  • switch式で網羅性チェック: sealed classes と組み合わせることで、コンパイル時に網羅性をチェックできるのは大きなメリットです。これにより、後から型が増えた際の見落としを防げます。
  • break文/continue文: ループ処理内でif文と組み合わせて、ループの継続や中断を行うことがあります。これらの制御文も適切に使いこなしましょう。

if文はシンプルですが、プログラムの振る舞いを決定する上で非常に重要な役割を果たします。基本をしっかり押さえ、switch式やsealed classesのような新しい機能も活用して、より堅牢で読みやすいコードを目指していきましょう!

コメント

タイトルとURLをコピーしました