条件分岐

編集

「条件分岐」は、プログラミングにおいて重要な概念の一つです。条件分岐を使うことで、プログラムは特定の条件に応じて異なる処理を実行することができます。

この章では、Javaでの条件分岐の基本的な使い方から、より高度な使い方までを解説します。if-else文、switch文、switch式、論理演算子、三項演算子など、様々な種類の条件分岐について学ぶことができます。また、例外処理における条件分岐の使い方についても解説します。

各セクションでは、実際のコード例を使って、どのように条件分岐を使えばよいかを説明します。また、練習問題も用意していますので、理解を深めるために挑戦してみてください。

条件分岐は、プログラムの制御構造を理解する上で重要な概念です。本章を通して、条件分岐の基本的な使い方から応用までを学び、プログラムの制御構造を理解してください。

if-else文

編集

Javaのif-else文は、プログラムの流れを条件分岐させるための文です。条件に応じて実行される文を切り替えることができます。

if文は、指定された条件が真である場合に実行される文を指定します。if文が偽である場合に実行される文を指定するために、else節を組み合わせて使うことができます。

if-else文の基本構文は以下の通りです。

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

条件式は、真偽値を返す式です。もし条件式が真であれば、if文の中の文が実行され、偽であればelse節の中の文が実行されます。

また、else節は省略することができます。省略した場合、条件式が偽である場合には何も実行されません。

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

複数の条件を判定する場合には、else if節を使うことができます。

if (条件式1) {
    // 条件式1が true の場合に実行される文
} else if (条件式2) {
    // 条件式1が false かつ、条件式2が true の場合に実行される文
} else {
    // 条件式1も条件式2も false の場合に実行される文
}

複数の条件を判定する場合には、if-else文をネストして使うこともできます。

public class IfElseExample {
    public static void main(String[] args) {
        var n = 0.0 / 0.0;

        if (n < 0.0) {
            System.out.println("負の数です");
        } else if (n > 0.0) {
            System.out.println("正の数です。");
        } else if (n == 0.0) {
            System.out.println("零です。");
        } else {
            System.out.println(n + "です。");
        }
    }
}

このコードは、if-else文を使って変数nが負の数、正の数、零、またはNaN(非数)であるかを判定しています。

まず、変数nに0.0を0.0で割った結果を代入しています。0.0を0.0で割るとNaNになるため、この変数はNaNになります。

次に、if-else文を使って、nが負の数、正の数、零、またはNaNであるかを判定しています。

まず、n < 0.0という条件を使って、nが負の数であるかを判定しています。もしnが負の数であれば、System.out.println("負の数です");が実行されます。

次に、n > 0.0という条件を使って、nが正の数であるかを判定しています。もしnが正の数であれば、System.out.println("正の数です。");が実行されます。

次に、n == 0.0という条件を使って、nが零であるかを判定しています。もしnが零であれば、System.out.println("零です。");が実行されます。

最後に、else節を使って、nがNaNであるかを判定しています。NaNはどの数とも等しくならないため、n == 0.0n < 0.0n > 0.0のいずれの条件も成立しないため、else節が実行されます。else節では、nの値をそのまま表示するSystem.out.println(n + "です。");が実行されます。

このように、if-else文を使うことで、複数の条件を判定し、条件に応じた処理を行うことができます。

switch文

編集

Javaのswitch文は、複数の条件分岐を処理するための構文です。特定の変数の値をチェックし、その値に応じて分岐することができます。

基本的な構文は以下の通りです。

switch () {
    case 値1:
        // 値1に対する処理
        break;
    case 値2:
        // 値2に対する処理
        break;
    default:
        // 上記のいずれの値にも一致しない場合の処理
        break;
}

式には、チェックする式を指定します。各caseには、変数が持つ値が一致する場合に実行される処理を記述します。defaultには、上記のいずれの値にも一致しない場合に実行される処理を記述します。

式には、数値以外に文字列も使うことが出来ます。

以下は、Javaのswitch文で文字列型を使用した例です。

public class SwitchStringExample {
    public static void main(String[] args) {
        String fruit = "りんご";
        
        switch (fruit) {
            case "りんご":
            case "バナナ":
            case "いちご":
            case "メロン":
                System.out.println(fruit + "は好きな果物です");
                break;
            default:
                System.out.println(fruit + "は果物ではありません");
                break;
        }
    }
}

この例では、変数fruitに文字列型の「りんご」が代入されています。switch文の条件式であるswitch (fruit)では、文字列型の変数fruitを使用しています。

switch文のcaseラベルには、文字列型の定数をカンマで区切って列挙しています。 また、caseラベルで果物として認識する文字列は、同じ文の中に複数記述することができます。 break文を使用して、該当するcaseラベルにマッチした場合は、それに続く文を実行するようにしています。

また、Javaのswitch文では、Enumを使った網羅性の確保ができます。Enumは、プログラムで扱う定数を列挙するためのクラスです。

以下は、Enumを使ったswitch文の例です。

import java.util.*;

public class SwitchEnumExample {
    public enum Animal {
        DOG,
        CAT,
        CANARY
    }

    public static void main(String[] args) throws Exception {
        Animal animal = Animal.CAT;

        switch (animal) {
            case DOG:
                System.out.println("ワンワン");
                break;
            case CAT:
                System.out.println("ニャー");
                break;
            case CANARY:
                System.out.println("ピューイ");
                break;
        }
    }
}

この例では、AnimalというEnumを定義し、それを使って動物の鳴き声を出力するプログラムを書いています。switch文のcaseには、Enumの要素を列挙しています。

switch文は、if文と比べて複数の条件分岐をスッキリと書くことができるため、コードの可読性が向上するという利点があります。

switch式

編集

Java 12から、Javaにはswitch式という新しい構文が導入されました。switch式は、通常のswitch文と同様に、複数の値の比較に基づいて異なるコードブロックを実行するために使用されますが、式の値を返すこともできます。

switch式は、通常のswitch文と同じように、いくつかのcaseブロックを持ちます。ただし、switch式では、個々のcaseラベルに式を直接使用できます。また、値を返すことができるため、式の値を変数に代入することもできます。

Javaのswitch式の構文は以下の通りです。

result = switch () {
    case 値1 -> 式1;
    case 値2 -> 式2;
    case 値3, 値4 -> {
        // multiple lines of expressions
        式3;
        yeild 式4;
    }
    default -> 式5;
};
  • switchキーワードに続いて、条件判定に用いる式を指定します。この式の結果に基づいて、次のcase文に分岐します。
  • caseキーワードに続いて、条件値を指定します。この条件値が、式の結果と等しい場合、その次の行に記述された式を実行します。
  • ->の後に続く式は、そのcaseで実行する処理を定義します。
  • 複数の条件値を一つのcase文で指定することもできます。この場合、条件値はコンマで区切って指定します。
  • 複数の式を実行したい場合は、中括弧 {} 内に複数の式を記述します。
    • この場合、ブロックの値は yeild 式の形で指定します。
  • defaultキーワードに続いて、どのcaseにも該当しない場合に実行する式を指定します。
  • 最後に、switch式の結果を代入する変数を指定します。代入は、=記号の左辺に変数名を、右辺にswitch式を指定します。

なお、switch式はJava 12から導入された新しい機能であり、以前のバージョンのJavaでは使用できません。

以下は、switch式の例です。

public class SwitchExpressionExample {
    public static void main(String[] args) {
        String fruit = "りんご";
        var result = switch (fruit) {
            case "りんご", "バナナ", "いちご" -> 1;
            case "メロン", "スイカ" -> 2;
            default -> 0;
        };
        System.out.println(fruit + "の評価結果は " + result);
    }
}

この例では、変数fruitに文字列型の「りんご」が代入されています。switch式では、変数fruitを評価しています。caseラベルには、直接式を使用しています。caseラベルで果物として認識する文字列は、同じ文の中にカンマで区切って複数記述することができます。->演算子を使用して、各caseラベルの式を実行します。

switch式の最後には、値を返すことができます。この例では、式の結果を変数resultに代入しています。最後に、変数resultの値を出力しています。

switch式はフォールスルーしません
switch文において、あえてbreak文を省略して、次のcaseの処理を実行することを「フォールスルー(fall-through)」と呼びます。

switch文でフォールスルーを行う場合は、明示的にコメントでその旨を記述することが推奨されます。

一方、switch式においては、フォールスルーの概念は存在せず、不用意な処理の続行を避けることができます。

論理演算子

編集

Javaにおいて、条件式は比較演算子や論理演算子を用いて、複数の条件を組み合わせた式を表現することができます。論理演算子は、2つのブーリアン値(trueまたはfalse)を受け取り、新しいブーリアン値を返します。

Javaには、5つの論理演算子があります。

  • 論理積(&&): 2つの式が両方ともtrueの場合にtrueを返します。例えば、式A && 式Bは、式Aがfalseの場合には評価を中止して、式Bを評価しません。
  • 論理和(||): 2つの式のどちらかがtrueの場合にtrueを返します。例えば、式A || 式Bは、式Aがtrueの場合には評価を中止して、式Bを評価しません。
  • 論理否定(!): 式がtrueの場合はfalseを、falseの場合はtrueを返します。例えば、!式Aは、式Aがfalseの場合にはtrueを返し、式Aがtrueの場合にはfalseを返します。
  • 排他的論理和(!=): 2つの式が不一致の場合にtrueを返します。短絡評価は行われません。
  • 排他的論理和(==): 2つの式が一致した場合にtrueを返します。短絡評価は行われません。

以下は、論理演算子(AND、OR、NOT)の真理値表を表形式で示したものです。

論理演算子の真理値表
A B !A A && B A || B
false false true false false
false true true false true
true false false false true
true true false true true

この表では、AとBがそれぞれ真(true)または偽(false)の場合に対する、NOT、AND、ORの結果が示されています。

三項演算子

編集

Javaの三項演算子は、条件式 ? 式1 : 式2 の形式を持ちます。この演算子は、条件式が true の場合は式1を、falseの場合は式2を評価して返します。例えば、以下のようなコードが考えられます。

var a = 5;
var b = 10;
var max = a > b ? a : b;
System.out.println("最大値は" + max);

このコードでは、aとbの値を比較して、aがbよりも大きければaを、そうでなければbを最大値として選択します。 三項演算子を使って、if文を使う代わりに簡潔に書くことができます。 ただし、三項演算子は条件式と2つの式のみを評価するので、複雑な条件分岐を行う場合にはif文を使用することが推奨されます。

パターンマッチング式

編集

Java 16で導入されたパターンマッチング式(Pattern Matching for instanceof)は、Java言語の制御構造の一つです。

通常、オブジェクトの型を判定するためには instanceof 演算子を使用します。パターンマッチング式は、この instanceof 演算子をより簡潔かつ安全に使用できるようにしたものです。

例えば、次のようなコードがあります。

if (obj instanceof String) {
    String str = (String) obj;
    System.out.println(str.toUpperCase());
}

このコードは、オブジェクトが String クラスのインスタンスである場合に、そのオブジェクトを String 型にキャストして大文字に変換し、標準出力に出力するという処理を行っています。

パターンマッチング式を使用すると、このコードを次のように書き換えることができます。

if (obj instanceof String str) {
    System.out.println(str.toUpperCase());
}

このコードでは、オブジェクトが String クラスのインスタンスである場合に、そのオブジェクトを String 型にキャストせずに、変数 str に直接代入しています。また、変数 str は if 文の中でのみ有効なローカル変数となります。

このように、パターンマッチング式を使用することで、より簡潔で安全なコードを書くことができます。

switchのパターンマッチング拡張

編集

switchのパターンマッチング拡張とは、Javaプログラミング言語において、switch文やswitch式においてパターンを使用して条件を指定できるようにする機能です。通常のswitch文やswitch式では、一致する値の厳密な等式比較しか行えませんでしたが、パターンマッチング拡張により、より柔軟な条件指定が可能になります。

具体的には、switch文やswitch式のケースラベルで、従来の定数だけでなく、パターンも指定できるようになります。これにより、オブジェクトの型や構造に基づいて条件を指定することができます。例えば、オブジェクトが特定の型であるか、あるいは特定のフィールドの値を持つかどうかなどの条件を指定することができます。

これにより、従来は複雑だった複数の条件分岐を一つのswitch文やswitch式で表現することができるようになり、コードの可読性が向上します。また、パターンマッチングにより、より安全な条件指定が可能になります。

以下は、Java 21で導入されたswitch文のパターンマッチング拡張を使用したコード例です。

public class PatternMatchingExample {
    public static void main(String[] args) {
        Object obj = "Hello";

        String result = formatterPatternSwitch(obj);
        System.out.println(result);
    }

    static String formatterPatternSwitch(Object obj) {
        return switch (obj) {
            case Integer i -> String.format("int %d", i);
            case Long l -> String.format("long %d", l);
            case Double d -> String.format("double %f", d);
            case String s -> String.format("String %s", s);
            default -> "unknown";
        };
    }
}

この例では、formatterPatternSwitchメソッド内で、switch文を使用してobjの型に基づいて処理を分岐しています。各ケースラベルでは、オブジェクトが特定の型にマッチするかどうかをパターンで指定しています。例えば、case Integer iでは、objInteger型にマッチする場合、iというパターン変数が導入され、その値がint %dのフォーマット文字列に埋め込まれます。他の型についても同様の処理が行われます。

このように、switch文のパターンマッチング拡張を使用することで、よりシンプルで効率的なコードを記述することができます。


以下は、Java 21で導入されたswitch文のパターンマッチング拡張で使用できるパターンの一覧を表形式で示したものです。

switchのパターンマッチング拡張で使用できるパターンの一覧
パターン 説明
型パターン 特定の型に一致するかどうかをチェックする。
nullパターン nullに一致するかどうかをチェックする。
リテラルパターン 指定されたリテラル値に一致するかどうかをチェックする。
列挙型定数パターン 指定された列挙型定数に一致するかどうかをチェックする。
配列パターン 指定された配列の要素の数と値に一致するかどうかをチェックする。
デコンストラクタパターン オブジェクトの構造を分解して、特定のフィールドや要素の値に一致するかどうかをチェックする。
インスタンスパターン 指定されたインスタンスのプロパティに一致するかどうかをチェックする。

これらのパターンを使用して、switch文やswitch式のケースラベルで条件分岐を行うことができます。それぞれのパターンは、特定の条件にマッチするかどうかをチェックするために使用されます。