daisuzz.log

JDK9以降のJavaの構文にふれてみる

Project Amberで検討されているJavaの言語仕様にふれてみます。

OpenJDK: Project Amber

今回触れるのは以下の言語仕様です。

環境

sdkmanを使ってJDK15のearly accessをインストールして、jshellを使ってコードを書いていきます。 jshell起動時に「--enable-preview」を付けないとpreview機能は使えないので注意が必要です。

$ sdk install java 15.ea.6-open
...
$ sdk use java 15.ea.6-open
...
$ java --version
openjdk 15-ea 2020-09-15
OpenJDK Runtime Environment (build 15-ea+6-123)
OpenJDK 64-Bit Server VM (build 15-ea+6-123, mixed mode, sharing)

$ jshell --enable-preview
|  JShellへようこそ -- バージョン15-ea
|  概要については、次を入力してください: /help intro

jshell>

JEP 286: Local-Variable Type Inference

JDK10から利用できます。 ローカル変数を型推論を使って宣言することができます。

jshell> class Person{
   ...>     String name;
   ...>     Person(String name){
   ...>       this.name = name;
   ...>     }
   ...>     String getName(){
   ...>       return this.name;
   ...>     }
   ...>   }
|  次を変更しました: クラス Person

jshell> var person = new Person("taro");
person ==> Person@799f7e29

jshell> person instanceof Person
$13 ==> true

JEP 323 Local-Variable Syntax for Lambda Parameters

JDK11から利用できます。 var をラムダの引数にも利用できます。varがラムダ の引数に使えるようになることで、ラムダ の引数にfinalやアノテーションをつけることができます。

jshell> var list = List.of(1,2,3);
list ==> [1, 2, 3]

jshell> List<Integer> result = list.stream().map((final var i)->i*2).collect(Collectors.toList());
result ==> [2, 4, 6]

JEP 325 Switch Expressions, JEP 354 Switch Expressions (Preview, JDK 13), JEP 361: Switch Expressions (Standard)

JDK12, 13ではpreviewとして、JDK14で正式に利用できます。 switchを式として使うことができます。また、今までの:を使ったラベルに加えて->を使ったラベルを書くことができます(arrow label)。

jshell> var str = "one";
str ==> "one"

jshell> int num = switch(str){
   ...> case "zero" -> 0;
   ...> case "one" -> 1;
   ...> case "two" -> 2;
   ...> default -> -1;
   ...> };
num ==> 1

switchのなかでブロックをそのまま使うとエラーになります。

jshell> var str = "one";
str ==> "one"

jshell> int num = switch(str){
   ...> case "zero" -> 0;
   ...> case "one" -> {
   ...>   1;
   ...> }
   ...> case "two" -> 2;
   ...> default -> -1;
   ...> };
|  エラー:
|  文ではありません
|    1;
|    ^
|  エラー:
|  switchルールが値を提供せずに完了しました
|    (switch式のswitchルールは値またはスローを提供する必要があります)
|  case "one" -> {
|                ^

この場合はyieldをつかって値を返すようにします。

jshell> var str = "one";
str ==> "one"

jshell> int num = switch(str){
   ...> case "zero" -> 0;
   ...> case "one" -> {
   ...>   yield 1;
   ...> }
   ...> case "two" -> 2;
   ...> default -> -1;
   ...> };
num ==> 1

JEP 355 Text Blocks, JEP 368: Text Blocks (Second Preview)

JDK13,14でpreviewとして利用できます。

jshell> String html = """
   ...>       <html>
   ...>         <body>
   ...>           <p>Hello world</p>
   ...>         </body>
   ...>       </html>
   ...>       """;
html ==> "<html>\n  <body>\n    <p>Hello world</p>\n  </body>\n</html>\n"

jshell> System.out.println(html);
<html>
  <body>
    <p>Hello world</p>
  </body>
</html>

JEP 305 Pattern Matching for instanceof

JDK14でpreviewとして利用できます。 instanceofを利用したパターンマッチングができます。 パターンマッチングで利用した変数は、マッチした場合のスコープ内で利用することができます。

jshell> class Person{
   ...>   String name;
   ...>   Person(String name){
   ...>     this.name = name;
   ...>   }
   ...>
   ...>   String getName(){
   ...>     return this.name;
   ...>   }
   ...> }
|  次を作成しました: クラス Person

jshell> var taro = new Person("taro");
taro ==> Person@7a07c5b4

jshell> if(taro instanceof Person p){
   ...>      System.out.println(p.getName());
   ...>    }
taro

JEP 359: Records (Preview)

JDK14でpreviewとして利用できます。 こんな感じで使えます。各フィールドにはフィールド名が名前になったメソッドでアクセスできます。

jshell> record Person(String name, Integer age){}

jshell> var taro = new Person("taro", 20);
taro ==> Person[name=taro, age=20]

jshell> var name = taro.name();
name ==> "taro"

jshell> var age = taro.age();
age ==> 20

jshell> var anotherTaro = new Person("taro", 20);
anotherTaro ==> Person[name=taro, age=20]

jshell> taro.equals(anotherTaro);
$9 ==> true

参考資料