switch文は制御フローの文であり、一致するcaseに遭遇したときに実行されるコードのブロックを指定することができます。switch文は、if-else文の代わりとして、特に複数の条件をテストするときによく使用されます。
switch文はreturnを書くことはできませんが、Java14以降では、switch式として値を返すことができるようになりました。ここではswitch文について解説します。
以下は、Javaにおけるswitch文の基本的な構文です。
switch (条件式) {
case value1:
// 条件式 == value1 のときに実行されるコード
break;
case value2:
// 条件式 == value2 のときに実行されるコード
break;
...
default:
// マッチしない場合に実行されるコード
}
式は評価され、各caseの値と比較されます。一致するものがあれば、そのcaseに関連するコードブロックが実行されます。マッチしない場合は、デフォルトに関連付けられたコードブロックが実行されます。
処理を分岐するcase値に使えるのは以下の条件を満たしている必要があります。
case値にnullや変数を指定するとコンパイルエラーがおきます。ただ、final宣言をした定数の場合はcase値にできます。
また、各caseブロックの最後にbreak文を入れることが重要です。これによりswitch文が終了し、コードが次のcaseブロックで実行されるのを防ぐことができます。
もしbreakがないと当てはまったcaseブロックの処理を実行後、それ以降のcaseブロックの処理をすべて実行してしまいます。これをフォールスルーと言います。複数のcaseに同じ処理をしたい場合など、意図的にフォールスルーさせたい場合は、コメントアウトで意図的であることを明示するべきでしょう。
それではdayの値によって、出力を変える処理を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");
}
この例では、変数dayの値が3であり、case 3と一致するため、switch文は"Wednesday"を文字列として出力します。
class Main {
public static void main(String[] args){
String fruit = "mango";
switch (fruit) {
case "apple":
System.out.println("This is an apple");
break;
case "banana":
System.out.println("This is a banana");
break;
case "orange":
System.out.println("This is an orange");
break;
default:
System.out.println("I don't know what fruit this is");
break;
}
}
}
switch文で変数fruitの値を指定されたcase値と比較します。もしfruitの値が"apple"であれば、最初のブロックのコードが実行されます。fruitの値が"banana"であれば、2番目のブロックのコードが実行され、以下同様となります。もし、どのケースもfruitの値と一致しない場合は、defaultのブロックのコードが実行されます。
switch文では、defaultを使用して、他のどのcaseも式の値と一致しない場合に実行されるコードブロックを指定します。defaultは任意で、switch文のどこにでも記述できますが、通常は末尾に記述します。defaultを途中で使う例を見てみましょう。
int x = 3;
switch (x) {
case 1:
System.out.println("x is 1");
break;
default:
System.out.println("x is not 1");
break;
case 2:
System.out.println("x is 2");
break;
}
この例では、xの値は3なので、どのcaseにもマッチしません。defaultのケースが実行され、"x is not 1"という文字列が出力されます。
特定のケースを最初に処理し、それ以外のケースをdefaultで処理したい場合など、defaultをswitch文の途中に配置することが有効な場合もあります。しかし、一般的には、switch文の最後にdefaultを配置した方が、より明確で読みやすいと言えます。
Javaのswitch文では、式は==演算子を使用して比較できる型である必要があります。これには、char、byte、short、int、Character、Byte、Short、Integer、String、および列挙型が含まれます。
また、double型や整数型でもlong型の値となるような式は利用できない点に注意が必要です。例えば、doubleの値をswitch文の中で使いたい場合は、switch文がサポートしているデータ型に変換する必要があります。
それでは例を見てみましょう。
double value = 3.14;
int intValue = (int) value;
switch(intValue) {
case 3:
System.out.println("The value is 3");
break;
case 4:
System.out.println("The value is 4");
break;
default:
System.out.println("The value is not 3 or 4");
break;
}
この例では、double 型の値を型キャストによってint型に変換しています。これにより、intデータ型のみをサポートするswitch文の中で値を使用することができます。
switch文は入れ子にして使うこともできます。ネストした内側のswitch文から外側のswitch文を抜けるときには outer というラベルをつけて抜けたいswitchを指定します。
class Main {
public static void main(String[] args){
int i = 3;
String s = "a";
outer: switch(i) { // ラベルを付けておく
case 3:
switch(s) {
case "a":
System.out.println("a");
break outer; // 外側のswitchも抜ける
default:
System.out.println("not a");
break;
}
System.out.println("3");
break;
default:
System.out.println("not 3");
break;
}
}
}
Javaのenumは、複数の定数のセットを定義するために使用される特殊なデータ型で、列挙型といいます。enumの実態はクラスで、フィールドやメソッドを持つことができますが、インスタンスを作ることはできません。
public enum Color {
RED,
GREEN,
BLUE
}
この例では、enumはRED、GREEN、BLUE の3つの値を持っています。これらの値は列挙子と呼ばれ、「列挙型名.列挙子名」という形で呼び出せます。
enumは他の変数と同じように使用できますが、使用できる値はenumで定義されたものに限られます。例えば、次のようにswitch文の中でenumを使用することができます。
class Main {
public enum Color {
RED(10), GREEN(20), BLUE(30);
int value; // フィールド
Color(int value) { // コンストラクタ
this.value = value;
}
public int getValue() { // メソッド定義
return this.value;
}
}
public static void printColor(Color color) {
switch (color) {
case RED:
System.out.println("The color is red and the value is " + color.getValue());
break;
case GREEN:
System.out.println("The color is green and the value is " + color.getValue());
break;
case BLUE:
System.out.println("The color is blue and the value is " + color.getValue());
break;
default:
System.out.println("Invalid color.");
break;
}
}
public static void main(String[] args){
System.out.println("Using enum.....");
// values()はenumで自動で定義されるメソッド 全ての定数を取得
for(Color c : Color.values()){
// ordinalは順番、nameは列挙子名を取得するenumのメソッド
System.out.println(c.ordinal() + ": " + c.name());
printColor(c);
}
}
}
switch文でenumを使うと、可読性、保守性、拡張性、安全性が向上するというメリットがあります。例えばcase値にリテラル(10やredなど)を入れると、その値が何を表しているのかわかりにくいですが、enumで値に名前を付けることで可読性が向上します。
また、enumで定義した列挙子以外を受け取ることができないので安全性を確保でき、データが増えた場合もenumに列挙子を追加するだけなのでメンテナンスがしやすくなります。
1つの変数や式に基づいて異なる動作をさせたいときに、一連のif文の代わりとして使用することができます。switch文は通常、入れ子になった一連のif文よりも簡潔で読みやすく、場合によってはより効率的に実行することができます。まずはif文を見てみましょう。
String fruit = "apple";
if (fruit.equals("apple")) {
System.out.println("This is an apple");
} else if (fruit.equals("banana")) {
System.out.println("This is a banana");
} else if (fruit.equals("orange")) {
System.out.println("This is an orange");
} else {
System.out.println("I don't know what fruit this is");
}
switch文では以下のように記述できます。
String fruit = "apple";
switch (fruit) {
case "apple":
System.out.println("This is an apple");
break;
case "banana":
System.out.println("This is a banana");
break;
case "orange":
System.out.println("This is an orange");
break;
default:
System.out.println("I don't know what fruit this is");
break;
}
比較したい変数や式が複数ある場合や、より複雑な比較を行う必要がある場合は、代わりにif文を使用するとよいでしょう。