Java switch 文
switch 文は、プログラムが単一の変数の値に基づいて異なるコードブロックを実行するための、非常にエレガントな手法を提供します。特定の固定された既知の値を処理する必要がある場合、冗長になりがちな if-else if-else チェーンに代わる完璧な選択肢となります。
switch 文をマスターすることは、効率的で読みやすいコードを書くために不可欠です。高度に構造化された方法で多重分岐に対応できるようになります。
1. switch 文を理解する
Java の switch 文は、一つの式(通常は変数)の値に基づいて、複数のコードブロックから実行するものを一つ選択します。この式は一度だけ評価され、その値が各 case ラベルで指定された値と順番に照合(マッチング)されます。一致するものが見つかれば、その case に属するコードブロックが実行されます。
1.1 基本的な構文構造
switch 文の基本構文は以下の通りです。
switch (expression) {
case value1:
// expression == value1 の場合に実行されるコード;
break;
case value2:
// expression == value2 の場合に実行されるコード;
break;
case valueN:
// expression == valueN の場合に実行されるコード;
break;
default:
// expression がどの case にも一致しない場合に実行されるデフォルトのコード;
}switch (expression): 括弧内のexpression(式) はチェックしたいターゲットです。データ型はbyte、short、int、char、String、またはenum(列挙型) に厳格に制限されています。case value1:: 各caseラベルは具体的な値を指定します。式の値がvalue1と完全に一致した場合、プログラムはこのラベルから下のコードを実行します。break;:breakステートメントは極めて重要です。その役割はswitch文を即座に終了させ、コードが次のcaseへ「フォールスルー(突き抜け)」するのを防ぐことです。これがないと、プログラムは以降の条件一致を無視して、次のcase内のコードを直接実行してしまいます。default::defaultラベルはオプショナル(任意)ですが、追加することを強く推奨します。式の値が上記のどのcaseにも一致しない場合、プログラムはdefault以降のコードを実行します。これはif-elseにおける最後のelseに似ています。
2. break の重要性:フォールスルー現象 (Fall-through) に注意
break ステートメントは switch 内部の実行フローを制御するスイッチです。これがないと、プログラムは フォールスルー (Fall-through) 現象を起こし、たとえ次の case の値が一致していなくても、そのまま次のコードを実行してしまいます。
極めて稀なギーク向けのシナリオでは意図的に利用されることもありますが、日常的な開発の 99% において、break の書き忘れは重大な バグ (Bug) の原因となります。
誤った例:
int day = 2;
String dayType;
switch (day) {
case 1:
dayType = "月曜日";
case 2:
dayType = "火曜日";
case 3:
dayType = "水曜日";
default:
dayType = "平日";
}
System.out.println(dayType); // 出力: 平日 (バグ!フォールスルーが発生)解析: この例では break ステートメントがないため、コードが case 2 にマッチした後、dayType に "火曜日" が代入されます。しかしそこで止まらず、そのまま下の case 3 を実行し、最後に default まで実行されます。最終的に dayType は "平日" に上書きされてしまい、意図に反する結果となります。
正しい書き方:各 case の後に break を追加
int day = 2;
String dayType;
switch (day) {
case 1:
dayType = "月曜日";
break; // マッチして実行された後、即座に switch を抜ける
case 2:
dayType = "火曜日";
break;
case 3:
dayType = "水曜日";
break;
default:
dayType = "平日";
}
System.out.println(dayType); // 出力: 火曜日 (完璧です!)3. switch がサポートするデータ型の実践
前述の通り、switch の式は特定のデータ型のみをサポートします。具体的な実戦デモンストレーションを見てみましょう。
3.1 整数型 (int)
int month = 4;
String monthString;
switch (month) {
case 1: monthString = "1月"; break;
case 2: monthString = "2月"; break;
case 3: monthString = "3月"; break;
case 4: monthString = "4月"; break;
// ... 5月から11月までを省略 ...
case 12: monthString = "12月"; break;
default: monthString = "無効な月";
}
System.out.println(monthString); // 出力: 4月3.2 文字型 (char)
char grade = 'B';
String gradeDescription;
switch (grade) {
case 'A': gradeDescription = "優秀"; break;
case 'B': gradeDescription = "良好"; break;
case 'C': gradeDescription = "普通"; break;
case 'D': gradeDescription = "合格"; break;
case 'F': gradeDescription = "不合格"; break;
default: gradeDescription = "無効なグレード";
}
System.out.println(gradeDescription); // 出力: 良好3.3 文字列型 (String)
String day = "Monday";
String activity;
switch (day) {
case "Monday": activity = "週の始まり"; break;
case "Tuesday": activity = "2日目"; break;
case "Wednesday": activity = "週の真ん中"; break;
case "Thursday": activity = "もう少しで週末"; break;
case "Friday": activity = "週末まであと少し"; break;
default: activity = "週末の予定";
}
System.out.println(activity); // 出力: 週の始まり3.4 列挙型 (enum)
まず、クラスの外部または内部で enum(列挙型) を定義します。
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}そして、switch 内でスムーズに使用します。
Day today = Day.WEDNESDAY;
String message;
switch (today) {
case MONDAY: message = "新しい一週間の始まり"; break;
case TUESDAY: message = "仕事2日目"; break;
case WEDNESDAY: message = "週の折り返し地点です!"; break;
case THURSDAY: message = "木曜日、頑張りましょう"; break;
case FRIDAY: message = "TGIF! 今日は金曜日です!"; break;
case SATURDAY: message = "週末万歳!"; break;
case SUNDAY: message = "のんびりした日曜日"; break;
default: message = "無効な日";
}
System.out.println(message); // 出力: 週の折り返し地点です!4. デフォルト分岐:default の役割
default 分岐は switch 文のオプショナルな部分です。すべての case がターゲット値と一致しない場合、この「フォールバック / 後備」オプションが提供されます。default を書く習慣をつけることで、無効な入力や未知の例外状況をエレガントに処理でき、コードを極めて 堅牢 (ロバスト) に保つことができます。
int number = 10;
String result;
switch (number) {
case 1: result = "一"; break;
case 2: result = "二"; break;
case 3: result = "三"; break;
default: result = "その他の数字";
}
System.out.println(result); // 出力: その他の数字 (10 は case に存在しないため)5. 高度な機能:Switch 式 (Java 12+)
Java 12 以降を使用している場合、switch は劇的に強化され、switch 式 (Switch Expressions) が導入されました。これによりコードがよりコンパクトになるだけでなく、値を直接返すことができるようになりました。
int day = 2;
// switch の結果を直接 dayType 変数に代入
String dayType = switch (day) {
case 1 -> "月曜日";
case 2 -> "火曜日";
case 3 -> "水曜日";
default -> "平日";
};
System.out.println(dayType); // 出力: 火曜日switch 式の圧倒的なメリット:
- アローラベル (->): 従来のコロン
:に代わって使用されます。 - break からの解放: アロー構文は本質的にフォールスルーを防止します。マッチングが完了すると値を返して終了するため、手動で
breakを書く必要がありません。 - 網羅性の強制 (Exhaustiveness): コンパイラがすべてのケースを処理しているか厳格にチェックします(enum の場合は全列挙、通常の型の場合は
defaultが必須)。これによりロジックの漏れを排除できます。 - 値を直接返す: アローの右側がその式の戻り値となります。
マッチング後に複雑なコード(複数行)を実行する必要がある場合は、波括弧 {} を使用し、yield キーワードを使用して値を返します。
int day = 5;
String dayType = switch (day) {
case 1 -> "月曜日";
case 2 -> "火曜日";
case 3 -> "水曜日";
case 4 -> "木曜日";
case 5 -> {
System.out.println("もうすぐ週末です!");
yield "金曜日"; // yield キーワードを使用して値を返す
}
default -> "無効な日";
};
System.out.println(dayType);
// 出力:
// もうすぐ週末です!
// 金曜日6. 実戦演習とデモンストレーション
知識を定着させるために、いくつかのリアルなビジネスシナリオのコードを見てみましょう。
6.1 例 1:簡易計算機
switch を利用して基本的な数学演算子を処理します。
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("最初の数字を入力してください: ");
double num1 = scanner.nextDouble();
System.out.print("演算子 (+, -, *, /) を入力してください: ");
char operator = scanner.next().charAt(0);
System.out.print("2番目の数字を入力してください: ");
double num2 = scanner.nextDouble();
double result = 0.0;
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
if (num2 != 0) {
result = num1 / num2;
} else {
System.out.println("エラー:ゼロで割ることはできません。");
return; // プログラム終了
}
break;
default:
System.out.println("無効な演算子です。");
return;
}
System.out.println("計算結果: " + result);
scanner.close();
}
}6.2 例 2:フォールスルーを利用した分岐の統合 (季節の判定)
フォールスルーはバグの原因と言いましたが、あえて利用することで複数の異なる値で同一のコードを共有させることができます。
public class SeasonChecker {
public static void main(String[] args) {
int month = 8;
String season;
switch (month) {
case 12: case 1: case 2: // 12, 1, 2月をまとめて処理
season = "冬";
break;
case 3: case 4: case 5:
season = "春";
break;
case 6: case 7: case 8:
season = "夏";
break;
case 9: case 10: case 11:
season = "秋";
break;
default:
season = "無効な月";
}
System.out.println(month + "月は " + season + " です。"); // 出力: 8月は 夏 です。
}
}6.3 例 3:カンマ区切りのモダンな Switch (週末の判定)
Java 14 以降、新しい switch 式を使用する場合、カンマを使用して複数の値を一行に記述でき、フォールスルーを利用するよりも直感的です。
public class DayTypeChecker {
public static void main(String[] args) {
int day = 6; // 1: 月曜, 2: 火曜, ..., 7: 日曜
String dayType = switch (day) {
case 1, 2, 3, 4, 5 -> "平日";
case 6, 7 -> "休日";
default -> "無効な日付";
};
System.out.println(day + "日目は " + dayType + " です。"); // 出力: 6日目は 休日 です。
}
}