Java 14で追加された16のJEP
2020年3月17日、Javaの最新版となるJava 14がリリースされた。このJava 14では、下記のような16のJEP(JDK Enhancement Proposal)が追加された。JEPの数だけで見れば、これは多くのJDKディストリビューターが長期サポート版に位置付けているJava 11に次ぐ大型のアップデートとなった。
- JEP 305: Pattern Matching for instanceof (Preview)
- JEP 343: Packaging Tool (Incubator)
- JEP 345: NUMA-Aware Memory Allocation for G1
- JEP 349: JFR Event Streaming
- JEP 352: Non-Volatile Mapped Byte Buffers
- JEP 358: Helpful NullPointerExceptions
- JEP 359: Records (Preview)
- JEP 361: Switch Expressions (Standard)
- JEP 362: Deprecate the Solaris and SPARC Ports
- JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
- JEP 364: ZGC on macOS
- JEP 365: ZGC on Windows
- JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination
- JEP 367: Remove the Pack200 Tools and API
- JEP 368: Text Blocks (Second Preview)
- JEP 370: Foreign-Memory Access API (Incubator)
これらのうち、「Preview」や「Incubator」となっているものは、近い将来正式に採用される予定ではあるが、現時点ではまだ試験的な導入に留まっている機能である。すでに使用できるものの、あくまでも試験的な扱いなので、今後まだ仕様が変更される可能性もある。一方「Standard」とついているのは、これまで試験的な導入だったものが、本バージョンから正式に採用されたことを意味している。
なお、JEPについての説明や開発ツールであるJDKのダウンロードなどについては、本連載の第1回および第2回の記事を参照いただきたい。
switch式を使ってみよう
今回追加された機能には、一般のJavaプログラマーにとっても極めて重要なものがいくつか含まれているが、JEP 361のswitch式もその1つと言えるだろう。switch式はJava 12で最初のプレビュー版であるJEP 325が導入され、2番目のプレビュー版であるJava 13のJEP 354を経て、今回のJEP 361で正式な採用となった。
従来のJavaプログラムでは、switchは文(Statement)としてしか記述できなかった。それに対し、JEP 361はswitchを式(Expression)として使用できるようにしようという拡張である。
まず、従来のswitch文の使い方をおさらいしてみよう。下記の例では、変数dayの値がcaseで指定されたラベルの値と一致したら、その部分の処理が実行される。なお、SUNDAYやMONDAYなどの曜日はjava.util.Calendarクラスに定義されたフィールド値を想定している。
従来のswitch文
switch(day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
System.out.println("(´Д`)");
break;
case FRIDAY:
System.out.println("ヽ(・∀・)ノ");
break;
case SATURDAY:
case SUNDAY:
System.out.println("ヽ(*´∀`)ノ");
break;
default:
System.out.println("(-_-)");
break;
}
JEP 361では、switchを式として使えること以外にもいくつかの便利な記述法が追加された。まず、caseのラベルに複数の値をカンマで繋いで指定できるようになった。上の例の場合、MONDAYからTHURSDAY、そしてSATURDAYとSUNDAYは同じ内容の処理になるので、次のように書き換えることができる。
caseのラベルに複数の値を指定できるようになった
switch(day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY:
System.out.println("(´Д`)");
break;
case FRIDAY:
System.out.println("ヽ(・∀・)ノ");
break;
case SATURDAY, SUNDAY:
System.out.println("ヽ(*´∀`)ノ");
break;
default:
System.out.println("(-_-)");
break;
}
また、処理部分を「:」ではなくラムダ式のように「->」を使ったアロー構文で記述できるようになった。この場合、breakを書かなくても次のcase処理にフォールスルーすることはない。処理が複数行にわたる場合には、{}で囲ってブロック化すればよい。
ラムダ式のように->を使って処理を書けるようになった
switch(day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY
-> System.out.println("(´Д`)");
case FRIDAY
-> System.out.println("ヽ(・∀・)ノ");
case SATURDAY, SUNDAY
-> System.out.println("ヽ(*´∀`)ノ");
default
-> System.out.println("(-_-)");
}
そして肝心のswitch式だが、次のように「->」に続けて値を指定することで、switchの結果としてその値が返されるようになる。この例では、変数emotionにはdayの値に応じた文字列が格納されることになる。
switchを式として使えるようになった
String emotion = switch(day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY
-> "(´Д`)";
case FRIDAY
-> "ヽ(・∀・)ノ";
case SATURDAY, SUNDAY
-> "ヽ(*´∀`)ノ";
default
-> "(-_-)";
};
System.out.println(emotion);
switch式の注意点としては、caseが条件のすべてのパターンを網羅していなければならないことが挙げられる。この例では、変数dayに0以下や8以上の値が指定された場合はdefaultの処理が実行される。もしdefalutが用意されていない場合は、dayのすべてのパターンを網羅できていないことになるので、コンパイルエラーとなる。
さて、switch式は演算式など同様の扱いになるので、次のようにメソッドの引数部などにも記述することができる。
式なのでメソッドの引数部分に書くこともできる
System.out.println(
switch(day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY -> "(´Д`)";
case FRIDAY -> "ヽ(・∀・)ノ";
case SATURDAY, SUNDAY -> "ヽ(*´∀`)ノ";
default -> "(-_-)";
}
);
また、返す値は、「->」に対して直接指定するだけでなく、次のように「yiead」を使って指定することも可能となっている。実際には、yieldを使って値を返すのが基本的な仕様で、値を直接指定するやり方はそのシンタックスシュガー(簡易化された記述法)になる。
yieldで値を返すこともできる
String emotion = switch(day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY
-> "(´Д`)";
case FRIDAY
-> "ヽ(・∀・)ノ";
case SATURDAY, SUNDAY
-> "ヽ(*´∀`)ノ";
default -> {
System.out.println(day + " is not defined.");
yield "(-_-)";
}
};
System.out.println(emotion);
なお、アロー構文を使わずに従来のように「:」を使って処理を書いた場合でも、yieldで値を返せば式として扱われる。
-従来の記述方法でも、switchを式として使える
String emotion = switch(day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY:
yield "(´Д`)";
case FRIDAY:
yield "ヽ(・∀・)ノ";
case SATURDAY, SUNDAY:
yield "ヽ(*´∀`)ノ";
default:
System.out.println(day + " is not defined.");
yield "(-_-)";
};
System.out.println(emotion);
Java 14からのswitchは、式として使えるようになったことに加え、ラベルの複数指定やアロー構文などが追加されてかなり使い勝手がよくなったと言えるだろう。とくにアロー構文は、従来のswitch文でやりがちだったbreakの記述忘れというミスを防げるので、積極的に活用したいところだ。