Java 13新機能まとめ

Java 13が2019/9/17にリリースされています。
[Java SE 13 Platform JSR 388](http://openjdk.java.net/projects/jdk/13/spec/)

# ダウンロード

OpenJDKサイトからダウンロードできていました。
https://jdk.java.net/13/

現在はアーカイブサイトからダウンロードできます。
https://jdk.java.net/archive/

LTSではないので、検証目的以外には今からダウンロードする必要もないと思いますけど。
MacやLinuxでのインストールには[SDKMAN!](https://sdkman.io/)をお勧めします

Oracle OpenJDK以外に無償で商用利用できるディストリビューションとしては、次のようなものがあります。

- [AdoptOpenJDK](https://adoptopenjdk.net/?variant=openjdk13&jvmVariant=hotspot)
- [Azul Zulu Community](https://www.azul.com/downloads/zulu-community/?version=java-13-mts)
- [Liberica JDK](https://bell-sw.com/pages/downloads/)

LTSではないのでAmazon Correttoではリリースされないようです。

Oracle JDKは開発用途には利用できますが、商用利用にはJava SE Subscriptionを購入する必要があります。

- [Java SE Development Kit 13](https://www.oracle.com/java/technologies/javase-jdk13-downloads.html)

# JEP
変更はJEPとしてまとまっています。
https://openjdk.java.net/projects/jdk/13/

今回は5つほどJEPが入っています。
[JEP 350: Dynamic CDS Archives](http://openjdk.java.net/jeps/350)
[JEP 351: ZGC: Uncommit Unused Memory (Experimental)](http://openjdk.java.net/jeps/351)
[JEP 353: Reimplement the Legacy Socket API](http://openjdk.java.net/jeps/353)
[JEP 354: Switch Expressions (Second Preview)](http://openjdk.java.net/jeps/354)
[JEP 355: Text Blocks (Preview)](http://openjdk.java.net/jeps/355)

## [JEP 355: Text Blocks (Preview)](http://openjdk.java.net/jeps/355)
複数行の文字列リテラルがプレビューとして導入されました。

```java
String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;
```

スペースのエスケープなどが追加されて、Java 15で標準になります。
詳しい仕様はJava 14の説明のほうをみてください。
[Java 14新機能まとめ - Qiita](https://qiita.com/nowokay/items/ec85d97a7cecaaac8123)

## [JEP 354: Switch Expressions (Second Preview)](http://openjdk.java.net/jeps/354)
Switch文を式にします。

```java
int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};
```

Java 12と比べると、switch式で値を返す構文が`break`から`yield`になりました。  
Java 14で標準化されています。
詳しい仕様はJava 14の説明のほうをみてください。
[Java 14新機能まとめ - Qiita](https://qiita.com/nowokay/items/ec85d97a7cecaaac8123)

## [JEP 350: Dynamic CDS Archives](http://openjdk.java.net/jeps/350)

`-XX:ArchiveClassesAtExit`をつけることで実行時にCDSアーカイブを作成します。  
使い方はこちらが参考になると思います。  
[Java 13のDynamic CDSで想像以上に起動速度が速くなった - きしだのHatena](https://nowokay.hatenablog.com/entry/2019/10/17/224720)

試した感じでは、実行時ではなくふつうにCDSアーカイブ作った方が起動が速かった。
[Dynamic CDSよりJava10からある自力ダンプの方が起動が速い - きしだのHatena](https://nowokay.hatenablog.com/entry/2019/10/19/002351)

## [JEP 351: ZGC: Uncommit Unused Memory (Experimental)](http://openjdk.java.net/jeps/351)

ZGCでつかってないメモリが解放されるようになります。

## [JEP 353: Reimplement the Legacy Socket API](http://openjdk.java.net/jeps/353)

TCPソケットAPIを実装しなおして、Project Loomでの非同期処理に対応しています。

# API

APIもいくつか変更されています。

## String

TextBlocks関連のAPIが追加されています。  
ただし、Java 13の時点では`@Deprecated`指定されているだけでいつでも使えますが、Java 14では`--enable-preview`をつけたときにだけ使えるようになっています。

### formatted
`String.format`をインスタンスメソッドとして使えるようにする。

たとえば

```java
callQuery(String.format("select * from table where id=%d", id));
```

と書いていたものが

```java
callQuery("select * from table where id=%d".formatted(id));
```

のように書けて便利。
https://bugs.openjdk.java.net/browse/JDK-8203444

### translateEscapes
`\n`などをエスケープ文字として扱う。 
コードを見るとエスケープが入り混じってまぎらわしいですが、文字列中の`\n`が改行に変換されています。 

```sh

jshell> var s = "test\\ntest\\n"
s ==> "test\\ntest\\n"

jshell> System.out.println(s)
test\ntest\n

jshell> s.translateEscapes()
$18 ==> "test\ntest\n"

jshell> System.out.println(s.translateEscapes())
test
test
```

https://bugs.openjdk.java.net/browse/JDK-8223780

### stripIndent

インデントを取り除きます。

https://bugs.openjdk.java.net/browse/JDK-8223775

## Map.ofで要素数1のMapに対するget(null)がぬるぽ
JDK9で`Map.of`が追加されています。
JDK9、JDK10では要素数0のときは`Map0`、要素数1のとき`Map1`、要素数2以上のとき`MapN`のインスタンスが返っていて、`Map.of().get(null)`は`null`を返していました。

```sh
C:\Users\naoki>java\jdk\jdk-10.0.1\bin\jshell
|  JShellへようこそ -- バージョン10.0.1
|  概要については、次を入力してください: /help intro

jshell> Map.of().get(null)
$1 ==> null

jshell> Map.of(1,2).get(null)
$2 ==> null

jshell> Map.of(1,2,3,4).get(null)
|  java.lang.NullPointerException thrown
|        at ImmutableCollections$MapN.probe (ImmutableCollections.java:779)
|        at ImmutableCollections$MapN.get (ImmutableCollections.java:721)
|        at (#3:1)
```

JDK11で要素数0の場合も`MapN`を使うようになって`Map.of().get(null)`がぬるぽになってます。

```sh
C:\Users\naoki>java\jdk\jdk-11.0.1\bin\jshell
|  JShellへようこそ -- バージョン11.0.1
|  概要については、次を入力してください: /help intro

jshell> Map.of().get(null)
|  例外java.lang.NullPointerException
|        at Objects.requireNonNull (Objects.java:221)
|        at ImmutableCollections$MapN.get (ImmutableCollections.java:843)
|        at (#1:1)

jshell> Map.of(1,2).get(null)
$2 ==> null

jshell> Map.of(1,2,3,4).get(null)
|  例外java.lang.NullPointerException
|        at ImmutableCollections$MapN.probe (ImmutableCollections.java:926)
|        at ImmutableCollections$MapN.get (ImmutableCollections.java:846)
|        at (#3:1)
```

`Map.of(1,2).get(null)`の場合はJDK9からJDK12まで`null`を返していました。
JDK13からは`Map.of(1,2).get(null)`も ぬるぽになります。  
以前のバージョンもJDK12.0.2や、JDK11.0.4で修正されています。

http://mail.openjdk.java.net/pipermail/core-libs-dev/2019-April/059533.html

ここで、nullチェックのためにrequireNonNullじゃなくてequals呼び出しを使ってるところも面白いですね。

http://cr.openjdk.java.net/~smarks/reviews/8221924/webrev.0/src/java.base/share/classes/java/util/ImmutableCollections.java.patch

### Numberのデフォルトコンストラクタ
http://mail.openjdk.java.net/pipermail/core-libs-dev/2019-May/060258.html

`Number`クラスにデフォルトコンストラクタが追加されました。
といっても実装はこんな感じです。

```sh
public Number() {super();}
```

これ、定義しなくても暗黙で定義されるので不要ですよね。
なんかlintをだまらせるために追加したっぽい

## JapaneseEraへの令和の追加

2019/5/1に新しい元号「令和」が始まりました。
Java 8のアップデートやJava 11、Java 12でもフォーマットやパースでは令和に対応していたのですが、JapaneseEraには正式には定義されていませんでした。
Java 13から`JapaneseEra.REIWA`が使えるようになりました。

Java 11では元号は決まっていなかったのでNewEraとして表示されていました。

```sh
jshell> java.time.chrono.JapaneseDate.now()
$1 ==> Japanese NewEra 2-07-21
```

11.0.3では元号が決まっていたのでREIWAという表示になりました。

```sh
jshell> java.time.chrono.JapaneseDate.of(2020,5,1)
$1 ==> Japanese Reiwa 2-05-01
```

これに対する`JapaneseEra.NEWERA`や`JapaneseEra.REIWA`も定義されてはいたのですが、package privateになっていてコードから使えなかったのですが、Java 13からはpublicになって誰でも使えるようになりました。

# ツール

rmicに少し変更が入っています。

## rmicで--preview-featureがついたものを通さないようにする
http://mail.openjdk.java.net/pipermail/core-libs-dev/2019-April/059683.html

## rmicをdeprecatedに。そしてそのうち消す
[\[JDK-8217412\] deprecate rmic for removal - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8217412)

Java 15で消えています。