プログラミング言語における「式」と「文」の違い。そしてswitch式が便利。
環境
- JDK 14以降
式と文の違い
プログラミングにおいて、「式(expression)」と「文(statement)」は似て非なるものです。
Javaの文法の仕様書であるJava Language Specification(略して「JLS」)を確認してみます。
文については、Chapter 14. Blocks, Statements, and Patternsの冒頭に
The sequence of execution of a program is controlled by statements, which are executed for their effect and do not have values.
訳: プログラムの実行シーケンスは、効果を目的として実行され値を持たない文によって制御されます。
とあります。
対して式については、Chapter 15. Expressionsの冒頭に
Much of the work in a program is done by evaluating expressions, either for their side effects, such as assignments to variables, or for their values, which can be used as arguments or operands in larger expressions, or to affect the execution sequence in statements, or both.
訳: プログラム内の作業の多くは、式を評価することによって行われます。式は、変数への割り当てなどの副作用、またはより大きな式の引数やオペランドとして使用したり、文の実行シーケンスに影響を与えたりするために使用できる値、あるいはその両方を評価します。
とあります。
つまり、「式」は値として評価でき、「文」は値を持たないというのが大きな違いです。
式は値として評価できる
例えば、変数への値の代入は「式」です。
int a;
// これは式なので「1」という値として評価できる
a = 1;
上記のa = 1は「1」という値として評価できるため、例えば以下のように他の式の一部として使用することもできます。(プログラムが複雑になるので普通はしません)
int a;
// aに1を代入し、その値を使ってbを初期化(bは3になる)
int b = (a = 1) + 2;
一方、if文やfor文などの制御フローは「文」です。これらは値を持たないため、変数に代入できません。
なので、下記の例のようなことはできません。もしできたら便利なんですけどねえ(「if式」があってコレができるプログラミング言語もあります)。
int a = 1;
// これはコンパイルエラー
int b = if (a > 0) {
1;
} else {
2;
};
switch式の便利さ
Java 14で、switch文に加えてswitch式が導入されました。例を見てみましょう。
まずswitch文の例です。
こんな曜日の列挙型があるとします。
public enum DayOfWeek {
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
}
そして、この列挙型を使ったswitch文は以下のようになります。
DayOfWeek day = DayOfWeek.WEDNESDAY;
String dayName;
switch (day) {
case SUNDAY:
dayName = "日曜日";
break;
case MONDAY:
dayName = "月曜日";
break;
case TUESDAY:
dayName = "火曜日";
break;
case WEDNESDAY:
dayName = "水曜日";
break;
case THURSDAY:
dayName = "木曜日";
break;
case FRIDAY:
dayName = "金曜日";
break;
case SATURDAY:
dayName = "土曜日";
break;
default:
dayName = "ちがいます";
}
System.out.println(dayName); // "水曜日"
switch文には、いくつかビミョーなところがあります。
-
dayName変数を事前に宣言だけしないといけない -
breakを必ず書かないといけない(書き忘れるとバグる) - enumの定数が全て網羅されているかは、人間が目で確認するしかない
- そして心配なので念の為の
default句を追加する
- そして心配なので念の為の
一方、switch式を使うと、以下のように書けます。
DayOfWeek day = DayOfWeek.WEDNESDAY;
String dayName = switch (day) {
case SUNDAY -> "日曜日";
case MONDAY -> "月曜日";
case TUESDAY -> "火曜日";
case WEDNESDAY -> "水曜日";
case THURSDAY -> "木曜日";
case FRIDAY -> "金曜日";
case SATURDAY -> "土曜日";
};
System.out.println(dayName); // "水曜日"
更に、caseでenumの全定数を網羅していない場合はコンパイルエラーになります。
String dayName = switch (day) {
case SUNDAY -> "日曜日";
case MONDAY -> "月曜日";
case TUESDAY -> "火曜日";
case WEDNESDAY -> "水曜日";
case THURSDAY -> "木曜日";
case FRIDAY -> "金曜日";
// SATURDAYが無い
};
エラー:
switch式がすべての可能な入力値をカバーしていません
String dayName = switch (day) {
^-------------...
つまり、switch式の場合は
-
dayName変数を宣言して、そのままswitch式の結果で代入・初期化できる! -
break不要! - enumの全定数を網羅していない場合コンパイルエラーになる!人間の目で確認する必要なし!
とてもうれしいですね!
Discussion