PR

Java:Switch文による条件分岐の基本とコツを3分で解説

Java

Javaのプログラムを書くときに、指定した条件に応じて異なる処理を行うことがよくあります。基本的にはif文を使うこともできますが、複数の条件を扱うときにはswitchを使うとコードがすっきりして読みやすくなる場合があります。

参考 Java:if文で条件分岐5つのポイントを3分で解説

switch文とは、ある値に基づいて異なるコードを実行するための構文です。例えば、曜日を表す数値に応じて「月曜日」「火曜日」といった文字列を表示するようなイメージ。この文を使うと、条件ごとにコードを書く代わりに、まとめてシンプルに書くことができます。

public class SwitchSample {
    public static void main(String[] args) {
        int day = 3; // 曜日を表す(1 = 月曜, 2 = 火曜, ...)

        switch (day) {
            case 1:
                System.out.println("月曜日です");
                break;
            case 2:
                System.out.println("火曜日です");
                break;
            case 3:
                System.out.println("水曜日です");
                break;
            case 4:
                System.out.println("木曜日です");
                break;
            case 5:
                System.out.println("金曜日です");
                break;
            case 6:
                System.out.println("土曜日です");
                break;
            case 7:
                System.out.println("日曜日です");
                break;
            default:
                System.out.println("無効な曜日です");
                break;
        }
    }
}

// 出力:水曜日です

このページでは、switch文の基本的な使い方についてわかりやすくご説明します。

スポンサーリンク

Java:Switch文の基本

switch文は、複数の条件分岐をスマートに書ける構文の1つです。if-else文と同じように条件分岐のために使われますが、大量のif-else if-else...を並べるよりも、読みやすく整理された形で書けるのがメリットです。

例えば、ある変数の値に応じて異なる処理を行いたいときに、以下のように書くと可読性が高くなります。

switch (式) {
    case 値1:
        // 値1の場合の処理
        break;
    case 値2:
        // 値2の場合の処理
        break;
    // 必要に応じてcaseを追加
    default:
        // どの値にも一致しない場合の処理
}

if-elseを多用して書いたのと同じ動作を、コンパクトに表現できるのが特徴です。

switch文の基本1:式

switch文の最初には、評価される「」を書きます。式と言っても、基本的には数値や文字列の変数を指定するだけです。ここでの式は、intbyteshortcharString、またはenumの型を持っている必要(要は、その式を何らかの形で評価できるかどうか)があります。

int day = 3;
switch (day) {
    // ここにcaseラベルと処理を書きます
}

switch文の基本2:Caseラベル

次に、caseラベルを使って、評価された式の値に基づく処理を記述します。各caseの後には、値と、それに対応する処理を書きます。

switch (day) {
    case 1:
        System.out.println("Monday");
        break;
    case 2:
        System.out.println("Tuesday");
        break;
    case 3:
        System.out.println("Wednesday");
        break;
    // 必要に応じて他のcaseを追加
}

↑変数 day の値に応じて、1の場合は「Monday」を。2の場合は「Tuesday」を。3の場合は「Wednesday」を出力するようにしています。

switch文の基本3:break文

caseの処理が終わった後には、break文を書きます。break文はswitch文を抜け出すためのものです。つまり、breakにきたらswitch文の処理をやめて次に移るということ。

これを忘れると、次のcaseの処理も実行されてしまう(フォールスルー)ので注意が必要です。

case 1:
    System.out.println("Monday");
    break; // ここでswitch文を抜ける

フォールスルーとは、caseブロック内にbreak文を書かずに次のcaseブロックの処理も続けて実行することです。これを使うと、似たような処理をまとめて書くことができるので、「あえて」フォールスルーを行うこともあります。

以下の例は、dayが1、2、3の場合に「Weekday」と表示されます。このように、複数のcaseが同じ処理を共有する場合にフォールスルーが有効になる場合があります。

int day = 2;

switch (day) {
    case 1: //case 1~2の場合にはbreakしない
    case 2:
    case 3:
        System.out.println("Weekday");
        break;
    case 4: //case 4の場合にもbreakしない
    case 5:
        System.out.println("Almost Weekend");
        break;
    case 6: //case 6の場合にもbreakしない
    case 7:
        System.out.println("Weekend");
        break;
    default:
        System.out.println("Invalid day");
}

フォールスルーについてはページ後半でも再度解説します。

switch文の基本4:Defaultラベル

最後に、defaultラベルを使って、どのcaseにも一致しなかった場合の処理を書くというのもポイント。これは必須ではなく任意なのですが、指定しておくと安心です。

int day = 3;

switch (day) {
    case 1:
        System.out.println("Monday");
        break;
    case 2:
        System.out.println("Tuesday");
        break;
    case 3:
        System.out.println("Wednesday");
        break;
    case 4:
        System.out.println("Thursday");
        break;
    case 5:
        System.out.println("Friday");
        break;
    case 6:
        System.out.println("Saturday");
        break;
    case 7:
        System.out.println("Sunday");
        break;
    default:
        System.out.println("Invalid day");
}
  • 構文:
    • switch (式) { case 値1: // 処理1; break; case 値2: // 処理2; break; default: // デフォルトの処理; }
  • :
    • switchキーワードの後に評価される式を書く。例: switch (day)
  • caseラベル:
    • 式の値に基づいて実行されるコードブロックを指定。例: case 1: // 処理;
  • break文:
    • caseの終了を示し、switch文から抜け出すために使用。例: break;
  • defaultラベル:
    • どのcaseラベルにも一致しない場合に実行されるコードブロックを指定。例: default: // デフォルトの処理;
Q
Javaのswitch式にはなんでlong型は使えないの?
A

Javaのswitch式(switch文を含む)でlong型が使えない理由は、主に実装のシンプルさとパフォーマンスの観点によるものです。以下のポイントで説明します。

1. switch の仕組み

Javaのswitchは、内部的に以下の2つの方法のどちらかで処理されます。

  • テーブル・スイッチ(tableswitch)
  • ルックアップ・スイッチ(lookupswitch)

これらはバイトコードレベルでswitchを最適化するための仕組みで、intcharなどの整数型が前提となっています。

2. long型はメモリ効率が悪い

  • tableswitchは、連続した値に対して高速に処理を行うために、ジャンプテーブル(配列のようなもの)を使います。
  • long型をサポートすると、このテーブルのサイズが大きくなりすぎ、メモリ効率が悪くなります。

3. パフォーマンスの問題

  • lookupswitchは、バラバラの値をサポートするために、キーとジャンプ先のアドレスをマップとして管理します。
  • long型はintより大きく、比較演算の負荷が増すため、switchのパフォーマンスが低下します。

4. if-elseで十分対応可能

  • long型の値を比較する場合、if-else文を使えば同じことができます。
  • switchlongをサポートする必要性が薄いため、仕様としてサポートされていません。

switch文とIf文の違い

ここまでswitch文を学んできましたが、実際はどれもif文でも記述できる処理です。じゃ、実際switch文とif文って何が違うの?っていう疑問が浮かぶ方もいるかもしれません。

ので、ここで同じコードをswitch文とif文で書くとそれぞれどうなるかを見てみましょう。

サンプル1 Switch文の場合

int day = 3;

switch (day) {
    case 1:
        System.out.println("Monday");
        break;
    case 2:
        System.out.println("Tuesday");
        break;
    case 3:
        System.out.println("Wednesday");
        break;
    case 4:
        System.out.println("Thursday");
        break;
    case 5:
        System.out.println("Friday");
        break;
    case 6:
        System.out.println("Saturday");
        break;
    case 7:
        System.out.println("Sunday");
        break;
    default:
        System.out.println("Invalid day");
}

サンプル2 If文の場合

int day = 3;

if (day == 1) {
    System.out.println("Monday");
} else if (day == 2) {
    System.out.println("Tuesday");
} else if (day == 3) {
    System.out.println("Wednesday");
} else if (day == 4) {
    System.out.println("Thursday");
} else if (day == 5) {
    System.out.println("Friday");
} else if (day == 6) {
    System.out.println("Saturday");
} else if (day == 7) {
    System.out.println("Sunday");
} else {
    System.out.println("Invalid day");
}

ご覧のようにSwitch文の一番のメリットは、コードが見やすくなることです。特に複数の条件を扱う場合、switch文を使うとコードの構造がシンプルでわかりやすくなります。

また数値や文字列の比較において、switch文はif文より実行速度が速い場合があります。利用されるシーンや条件にも応じて変わるのですが、プログラムのパフォーマンスを改善する施策の一環としてif文→switch文にリファクタリングされる場合もあります。

一方で、switch文にはデメリットもあります。

まず、複雑な条件を扱うのには向いていません。複数の条件を組み合わせた複雑な判定を行う場合、switch文では表現しづらいかったりします。また、switch文で使用できるデータ型は限られており、int、byte、short、char、String、enumのみに対応しています。

ポイント If文 vs Switch文

  • switch文のメリット
    • 分岐する値(ケース)が明確に羅列されるため見やすい。
    • 変数の値に応じた単純分岐の場合にすっきり書ける。
  • if-else文のメリット
    • == だけでなく、不等号や複雑な論理式( &&, || )など、さまざまな条件が書ける。
    • 範囲指定(0 <= num && num < 10)のような条件分岐にはswitchより使いやすい。

Switch文の実践的な使い方と注意点

Javaのswitch文は、特定の条件に基づいて異なる処理を実行するのに非常に便利。最後に、現場でよくある使い方と注意点、ベストプラクティスについて説明します。

実践例1 ユーザー権限に応じたメニュー表示

実際の現場では、ユーザーの権限に応じて異なるメニューを表示したいような場合があります。このような場合にswitch文が役立ちます。

public class UserMenu {
    public static void main(String[] args) {
        String role = "editor"; // 例としてユーザーの役割を設定

        switch (role) {
            case "admin":
                System.out.println("管理者メニューを表示します");
                // 管理者向けの機能をここに追加
                break;
            case "editor":
                System.out.println("編集者メニューを表示します");
                // 編集者向けの機能をここに追加
                break;
            case "viewer":
                System.out.println("閲覧者メニューを表示します");
                // 閲覧者向けの機能をここに追加
                break;
            default:
                System.out.println("無効な役割です");
                // 無効な役割の場合の処理をここに追加
        }
    }
}

実践例2 商品カテゴリに応じた割引計算

商品カテゴリに応じて異なる割引を適用する場合の例です。

public class DiscountCalculator {
    public static void main(String[] args) {
        String category = "electronics"; // 商品カテゴリを設定
        double price = 100.0; // 商品の価格

        double discountPrice;

        switch (category) {
            case "electronics":
                discountPrice = price * 0.9; // 10%の割引
                System.out.println("電子機器カテゴリの割引価格: " + discountPrice);
                break;
            case "clothing":
                discountPrice = price * 0.8; // 20%の割引
                System.out.println("衣類カテゴリの割引価格: " + discountPrice);
                break;
            case "food":
                discountPrice = price * 0.95; // 5%の割引
                System.out.println("食品カテゴリの割引価格: " + discountPrice);
                break;
            default:
                System.out.println("無効なカテゴリです。割引なしの価格: " + price);
                // 無効なカテゴリの場合の処理をここに追加
        }
    }
}

まとめ JavaのSwitch文

  • 構文:
    • switch (式) { case 値1: // 処理1; break; case 値2: // 処理2; break; default: // デフォルトの処理; }
  • :
    • switchキーワードの後に評価される式を書く。例: switch (day)
  • caseラベル:
    • 式の値に基づいて実行されるコードブロックを指定。例: case 1: // 処理;
  • break文:
    • caseの終了を示し、switch文から抜け出すために使用。例: break;
  • defaultラベル:
    • どのcaseラベルにも一致しない場合に実行されるコードブロックを指定。例: default: // デフォルトの処理;
  • フォールスルー:
    • break文を省略して次のcaseの処理も続けて実行させることができる。
public class UserRole {
    public static void main(String[] args) {
        String role = "editor"; // ユーザーの役割を設定

        switch (role) {
            case "admin":
                System.out.println("管理者メニューを表示します");
                // 管理者向けの機能をここに追加
                break;
            case "editor":
                System.out.println("編集者メニューを表示します");
                // 編集者向けの機能をここに追加
                break;
            case "viewer":
                System.out.println("閲覧者メニューを表示します");
                // 閲覧者向けの機能をここに追加
                break;
            default:
                System.out.println("無効な役割です");
                // 無効な役割の場合の処理をここに追加
        }
    }
}

実践編:Switch文を使いこなすためのTips

ここからは実際にJavaの開発者として知っておきたい実践的な知識について補足していきます。

break文とfall-through

Javaのswitch文を使う上で大切な知識が、「break文を使わないと、後続のcaseの処理まで実行される」という特性です。これをフォールスルー (fall-through)と呼びます。※該当する case から順にすべての case の処理が実行されます。

サンプルコード break文を省略した場合

public class SwitchFallThrough {
    public static void main(String[] args) {
        int day = 2;

        switch(day) {
            case 1:
                System.out.println("月曜日");
            case 2:
                System.out.println("火曜日");
            case 3:
                System.out.println("水曜日");
            default:
                System.out.println("それ以外");
        }
    }
}

出力結果はどうなるでしょうか。day = 2 のとき、実行されるのは次の順序です。

  1. case 2: にマッチする
  2. しかしbreak; が無いため、次のcase 3:の処理も実行
  3. さらにbreak; が無いのでdefault:の処理まで連続して実行

したがって、結果的に

火曜日
水曜日
それ以外

が出力されます。これがJavaのswitch文特有のフォールスルーという動きです。C言語などでも同様の挙動があります。多くの場合は意図せぬ実行を避けるためにbreak;を書くのが一般的ですが、あえてフォールスルーを活用したい場合もあります。

default も含めて実行されるという点を頭に入れておきましょう!

フォールスルーを活用する例

複数のケースで処理が同じになる場合、フォールスルーを使うと以下のように書けます。

switch (num) {
    case 1:
    case 2:
    case 3:
        System.out.println("1か2か3のときの共通処理");
        break;
    default:
        System.out.println("それ以外のとき");
}

case 1: にマッチしたらcase 2:case 3:の処理が書いていなくとも「通り抜け」て同じブロックが実行されます。こうすることで、いくつかの値のときに同じ処理をまとめるのが容易になります。

caseは「入口」、breakは「出口」!

switch文のcaseは、それぞれの条件ごとに処理が始まる「入口」というイメージを持つと理解しやすいです。→switch (変数) の値に合うcaseが見つかると、そこから処理がスタート。必要なところでbreak(出口)を書いて区切るイメージ。

🔍 switch(値)
      ├── case 1:  ← 入口 (値が1ならここから実行)
      │     処理...
      │     break; ← 出口 (ここで処理終了)
      │
      ├── case 2:  ← 入口 (値が2ならここから実行)
      │     処理...
      │     break; ← 出口
      │
      ├── default: ← どのcaseにも当てはまらなかった時の入口
            処理...
int num = 2;

switch (num) {
    case 1:  // 入口1
        System.out.println("numは1です");
        break;  // 出口1
    case 2:  // 入口2
        System.out.println("numは2です"); // ここから処理開始
        break;  // 出口2
    case 3:  // 入口3
        System.out.println("numは3です");
        break;  // 出口3
    default: // どの入口にも合わないとき
        System.out.println("numは1,2,3以外です");
        break;
}
  • case は、それぞれの値に対応する「入口」。
  • break を忘れると、次のcaseの処理まで進んでしまう。
  • default は、どのcaseにも当てはまらないときの「入口」。

switch式 (Java 14以降)

Java 14以降では、switch文の拡張形としてswitch式が正式に追加されました。switch式を使うと、値を返すswitchを書くことができます。また、breakの書き忘れ防止などでコードの安全性・可読性が向上します。

従来のswitch文 (制御構文) とswitch式 (式として値を返すもの)

  • switch文 (従来)
    • 値を返さない。breakが必要。
    • フォールスルーに注意が必要。
  • switch式 (Java 14~)
    • 値を返す。case->を使う。
    • フォールスルーは原則的にしない。
    • yieldキーワードまたは->に続く式で値を返せる。
public class SwitchExpressionExample {
    public static void main(String[] args) {
        int num = 2;

        // switch式
        String result = switch (num) {
            case 1 -> "numは1です。";
            case 2 -> "numは2です。";
            case 3 -> "numは3です。";
            default -> "numは1,2,3以外です。";
        };

        System.out.println(result);
    }
}

switch (num) { ... } のあとに -> を使ってケースごとの「返す値」を直接書いています。

default -> ... を省略することもできますが、カバーされない値があればコンパイル時警告やエラーになる場合があります。enumなど網羅できる型の場合はdefault -> ... は省略しても問題ありませんが、基本的にはdefaultは必要である!と覚えておきましょう。

複数の値に対して同じ結果を返す

switch式では、複数のラベルを「,」区切りでまとめて書けます。次のように書くことで、フォールスルーを使わなくても同じ処理をまとめることができます。

int day = 1;
String dayType = switch(day) {
    case 1, 7 -> "週末";
    default -> "平日";
};

// これにより、1(=日曜)と7(=土曜)で同じ処理・結果を返せます。

enumを使ったswitch

Javaには列挙型(enum)があります。列挙型は定数の集合を表すのに便利です。switch文では、enumの各定数をcaseに指定して分岐が可能です。

public class EnumSwitchExample {
    // 列挙型を定義
    enum Season {
        SPRING, SUMMER, AUTUMN, WINTER
    }

    public static void main(String[] args) {
        Season current = Season.SPRING;

        switch(current) {
            case SPRING:
                System.out.println("春です");
                break;
            case SUMMER:
                System.out.println("夏です");
                break;
            case AUTUMN:
                System.out.println("秋です");
                break;
            case WINTER:
                System.out.println("冬です");
                break;
        }
    }
}
  • enum Season { ... }で列挙型Seasonを定義しています。
  • switchの判定式に Season 型の変数を指定すると、caseに列挙子(ここではSPRING, SUMMER, AUTUMN, WINTER)を並べられます。
  • default節は書かなくてもコンパイルエラーにはなりませんが、網羅性を確保するために書いておく方法もあります(ただし、enumで全列挙子をきちんと書いている場合は必須ではありません)。

列挙型を使うと、判定すべきパターンが増えたり減ったりしにくいことが多く、可読性や安全性の面でもよく利用されます。

ネストされたswitch文

switch文の内部で、さらに別のswitch文を呼び出す「ネスト」した構造を作ることも可能です。ただし、ネストが深くなると可読性が大幅に落ちるため、可能であれば設計・構造を見直すのがおすすめです。

public class NestedSwitchExample {
    public static void main(String[] args) {
        int outer = 1;
        int inner = 2;

        switch (outer) {
            case 1:
                System.out.println("outerは1です");

                switch (inner) {
                    case 1:
                        System.out.println("innerは1です");
                        break;
                    case 2:
                        System.out.println("innerは2です");
                        break;
                    default:
                        System.out.println("innerは1でも2でもありません");
                        break;
                }
                break;

            case 2:
                System.out.println("outerは2です");
                break;

            default:
                System.out.println("outerは1でも2でもありません");
                break;
        }
    }
}

ネストを多用すると「どこからどこまでがどの分岐なのか」が読み取りづらくなるので、条件分岐のロジックが複雑化しすぎないよう要注意です。大規模な分岐ロジックになりそうな場合は、より適切な設計パターン(多態性、Stateパターンなど)の導入を検討することをおすすめします。

まとめ 注意点・ベストプラクティス

  1. breakの書き忘れに注意
    フォールスルーを明示的に使いたい場合を除き、caseの末尾にbreak;を入れましょう。書き忘れによる不具合は初心者がつまずく代表的なポイントです。
  2. default節をなるべく書く
    予期しない値が来た場合の処理を決めておくと、バグ調査時にも原因が判明しやすくなります。特にユーザー入力を扱うような箇所では書いておいた方が安全です。
  3. 可読性を優先
    if-elseで十分な場合、switchにする必要はありません。また、switchのネストが深くなる場合、設計そのものを見直すべきケースが多いです。
  4. switch式を活用
    Java 14以降を使っている場合はswitch式が便利です。値を返すロジックを簡潔に書けるので、コードの管理や保守性が向上します。
  5. フォールスルーの使い方は慎重に
    フォールスルーは間違いやすいので、同じ処理をまとめたいときに限り意図的に使用しましょう。複数行の処理をフォールスルーでまとめると混乱しやすいため、できるだけ1行や1メソッド呼び出しにまとめると可読性が上がります。
  6. enumやStringのswitchを活用
    enumは安全で可読性が高いです。文字列でコマンドを判定するなど、switch文の利点を最大限に生かせるケースも多数あります。
タイトルとURLをコピーしました