Java 12新機能まとめ

すでにJava12はRampdownフェーズに入り、機能がほぼ確定しており、順調に行けば3月19日にリリースされます。->されました。
ということで、Java12に入る機能をJEP、API、その他にわけてまとめます。
[JDK 12 Early-Access Builds](http://jdk.java.net/12/)

# JEP
まずは大きな機能をまとめたJEPベースの変更
http://openjdk.java.net/projects/jdk/12/

全部で8個のJEPが入ってます。ふつうのJavaプログラマに影響ありそうなのは上の3つとDefault CDSですかね。残念ながらRaw String Literalsはドロップされました。
189: [Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)](http://openjdk.java.net/jeps/189)
230: [Microbenchmark Suite](http://openjdk.java.net/jeps/230)
325: [Switch Expressions (Preview)](http://openjdk.java.net/jeps/325)
334: [JVM Constants API](http://openjdk.java.net/jeps/334)
340: [One AArch64 Port, Not Two](http://openjdk.java.net/jeps/340)
341: [Default CDS Archives](http://openjdk.java.net/jeps/341)
344: [Abortable Mixed Collections for G1](http://openjdk.java.net/jeps/344)
346: [Promptly Return Unused Committed Memory from G1](http://openjdk.java.net/jeps/346)

それぞれについて、使いそう順に書いていきます。

## 325: [Switch Expressions (Preview)](http://openjdk.java.net/jeps/325)
Preview機能としてSwitch文が拡張されて、式として使えるようになりました。(Preview機能を使うには`javac`などに`--enable-preview`をつける必要があります)

```java
String time = switch (weekday) {
  case MONDAY, FRIDAY -> "10:00-18:00";
  case TUESDAY, THURSDAY -> "10:00-14:00";
  default -> "休日";
};
```
これは今までだとこんな感じになりますね。

```java
String time;
switch (weekday) {
  case MONDAY:
  case FRIDAY:
    time = "10:00-18:00";
    break;
  case TUESDAY:
  case THURSDAY:
    time = "10:00-14:00";
    break;
  default:
    time = "休日";
}
```

`switch`を使う多くの場合がこのようなパターンだったと思います。いままでのswitchでは、記述量が多いのはもちろんですが、break抜けや間違った変数を更新してしまう、更新の抜けがないことが保証されないといったバグの原因になっていました。これが解消されることになるため、積極的に使っていきたいところです。

実際には３つの仕様追加に分かれています。

### 複数case
`case`に複数の値を指定できるようになりました。

```java
String time;
switch (weekday) {
  case MONDAY, FRIDAY:
    time = "10:00-18:00";
    break;
  case TUESDAY, THURSDAY:
    time = "10:00-14:00";
    break;
  default:
    time = "休日";
}
```

### Rule Switch
`->`を使うことで、breakが不要になりました。

```java
String time;
switch (weekday) {
  case MONDAY, FRIDAY -> time = "10:00-18:00";
  case TUESDAY, THURSDAY -> time = "10:00-14:00";
  default -> time = "休日";
}
```

ブロックを使えば複数行の処理も行えます。

```java
String time;
switch (weekday) {
  case MONDAY, FRIDAY -> {
    var endTime = getEndTime();
    time = "10:00-" + endTime;
  }
  case TUESDAY, THURSDAY -> time = "10:00-14:00";
  default -> time = "休日";
}
```

これは積極的に使いたいですね。

### Switch式
そして、`switch`が式にもなりました。
アロー構文を使わない場合やアロー構文にブロックを使った場合は、`break`で値を返します。

```java
String time = switch (weekday) {
  case MONDAY, FRIDAY ->  {
    var endTime = getEndTime();
    break "10:00-" + endTime;
  }
  case TUESDAY, THURSDAY -> "10:00-14:00";
  default -> "休日";
};
```

すべての入力に対応できない場合はエラーになります。

```sh
jshell> switch("a"){ case "a" -> 3;}
|  エラー:
|  switch式がすべての可能な入力値をカバーしていません
|  switch("a"){ case "a" -> 3;}
|  ^--------------------------^
```

値を返す`break`は正式仕様になる際に`break-with`になる可能性がありました。
[Call for feedback -- enhanced switch](http://mail.openjdk.java.net/pipermail/amber-dev/2019-March/004126.html)
しかし、JDK 13では`yield`になっています。

## 341: [Default CDS Archives](http://openjdk.java.net/jeps/341)

クラスデータをあらかじめ作成して共有するという仕組みがあるのですが、いままでは `java -Xshare:dump`として一旦自分でクラスデータを作っておく必要がありました。
JDK12からは`lib/server/classes.jsa`があらかじめ含まれていて、この作業が不要になり、またJDK11で`-Xshare:auto`がデフォルトになっていて`classes.jsa`があれば自動でCDSが使われるようになってるので、なにもしなくても最初からCDSが使われるようです。
これで、Javaの起動時間が改善するはず。

## 189: [Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)](http://openjdk.java.net/jeps/189)
Red Hatが開発しているGCです。2GBでも200GBでも停止時間が変わらない、というのがウリっぽい。

G1GCと共通のコードが多いということで、Shenandoahの開発時にG1GCも改善できてしまったということが結構あるようです。
今回の[JEP346](http://openjdk.java.net/jeps/346)も、そんなShenandoah開発中の改善をG1GCに反映させたもののひとつです。
Java10での[Parallel Full GC for G1](http://openjdk.java.net/jeps/307)もそうみたい。
[InfoQ:レッドハットでのOpenJDKの未来](https://www.infoq.com/jp/news/2018/12/red-hat-openjdk-gc-Nov18)

さて、JDK11でも[ZGC](http://openjdk.java.net/jeps/333)と[Epsillon](http://openjdk.java.net/jeps/318)という2つのGCが入ってます。
ということで、JDK12には7つのGCが入ってるわけですね。

- Serial GC
- Parallel GC
- Concurrent Mark and Sweep (CMS)
- Garbage First GC (G1GC)
- Epsillon GC
- ZGC
- Shenandoah

デフォルトはJava9からG1GCになっています。
[JEP 248: Make G1 the Default Garbage Collector](http://openjdk.java.net/jeps/248)

ただし、メモリが少ない環境ではParallel GCが、シングルコア環境ではSerial GCが使われるようです。

ZGCは32GB以下のヒープでは使わないほうがよさそうなので、数百GBから数TBのヒープがあるときに使う感じだと思います。
G1GCとShenandoahの使い分けはどうなんでしょうね？

CMSはJava9から非推奨になっていて、将来的には削除される予定
[JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector](https://openjdk.java.net/jeps/291)

あと、サーバレスみたいにリクエストごとに起動するような場合はEpsilon GCがいいんでは、と思ったんだけど、試しに簡単なプログラムでEpsilon GC使ってみたところ遅くなってますね。

## 230: [Microbenchmark Suite](http://openjdk.java.net/jeps/230)
JMH(Java Microbenchmark Harness?)というベンチマークフレームワークがあるのですが、JDKに含まれるようになったようです。メンテナンスを同期させるため？
[OpenJDK: jmh](https://openjdk.java.net/projects/code-tools/jmh/)

ただ、外部のjmhを利用するのに比べて何がかわったか、どうやって使うかは、資料をみつけれてません。

## 334: [JVM Constants API](http://openjdk.java.net/jeps/334)

Java11でDynamic Class-File Constantsが入って、クラス初期化時の処理にInvokeDynamicが使えるようになりました。
[JEP 309: Dynamic Class-File Constants](http://openjdk.java.net/jeps/309)
けれども、このときは言語仕様やAPIは追加されなかったので、利用するには自分でクラスファイルを作成する必要がありました。

`java.lang.constant`パッケージが追加されて、`Constable`インタフェースや`ConstantDesc`インタフェースなどが追加されました。
そして`String`や`Integer`、`Class`や`Enum`など定数として使うなーというクラスが`Constable`を実装して`describeConstable()`メソッドを実装しています。

## 346: [Promptly Return Unused Committed Memory from G1](http://openjdk.java.net/jeps/346)
未使用のメモリをアイドル時に返却する。
Shenandoahでの変更のG1GCへの反映ぽい。

## 344: [Abortable Mixed Collections for G1](http://openjdk.java.net/jeps/344)

Mixed GCを停止可能にする。
これがShenandoah由来かどうかは知らない。

## 340: [One AArch64 Port, Not Two](http://openjdk.java.net/jeps/340)
ARM64bit用のPortとして、arm64とaarch64のふたつのソースコードがあったので、arm64のほうを消して作業の重複などをなくしたということらしい。

# API
APIの変更も派手なのはなく、ちょっとした修正がいくつか入ってる感じ。

## CompactNumberFormat
大きな数値を、たとえば10,000を1万とか10Kとかで表記する`NumberFormat`です。
[\[JDK-8188147\] Compact Number Formatting support - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8188147)

インスタンスは`java.text.NumberFormat`の`getCompactNumberInstance`メソッドで取得します。
日本ロケールの場合はこんな感じ。兆まで対応してて京は未対応な感じですね。

```sh
jshell> import java.text.*

jshell> var cnf = NumberFormat.getCompactNumberInstance()
cnf ==> java.text.CompactNumberFormat@73cf7357

jshell> cnf.format(10000)
$4 ==> "1万"

jshell> cnf.format(10000_0000)
$5 ==> "1億"

jshell> cnf.format(10000_0000_0000L)
$6 ==> "1兆"

jshell> cnf.format(10000_0000_0000_0000L)
$7 ==> "10000兆"
```
ロケールを指定する場合は、スタイルも指定する必要があります。`SHORT`か`LONG`かが選べます。
`SHORT`だとこんな感じ。

```sh
jshell> cnf = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT)
cnf ==> java.text.CompactNumberFormat@952071d5

jshell> cnf.format(1000)
$9 ==> "1K"

jshell> cnf.format(1000_000)
$10 ==> "1M"

jshell> cnf.format(1000_000_000)
$11 ==> "1B"

jshell> cnf.format(1000_000_000_000L)
$12 ==> "1T"

jshell> cnf.format(1000_000_000_000_000L)
$13 ==> "1000T"
```
Tまで対応しています。あれ10億は1Gじゃないの？という感じですね。
では`LONG`を指定してみましょう。

```sh
jshell> cnf = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.LONG)
cnf ==> java.text.CompactNumberFormat@38c39d6b

jshell> cnf.format(1000)
$15 ==> "1 thousand"

jshell> cnf.format(1000000)
$16 ==> "1 million"

jshell> cnf.format(1000000000)
$17 ==> "1 billion"

jshell> cnf.format(1000000000000L)
$18 ==> "1 trillion"

jshell> cnf.format(1000000000000000L)
$19 ==> "1000 trillion"
```

1000の場合はKiloのKだったようですが、MやTはMegaやTeraではなくMillionやTrillionだったようです。

小数点以下を表示したいときは`setMaximumFractionDigit`や`setMinimumFractionDigit`を使います。
デフォルトでは小数点以下は四捨五入されます。

```sh
jshell> cnf.format(123456)
$20 ==> "123 thousand"
```

`setMaximumFractionDigits`を使うと小数点以下の桁数の最大を指定できます。

```sh
jshell> cnf.setMaximumFractionDigits(2)

jshell> cnf.format(123456)
$21 ==> "123.46 thousand"

jshell> cnf.format(123400)
$22 ==> "123.4 thousand"
```

`setMinimumFractionDigits`を使えば小数点以下の桁数の最小を指定できます。

```sh
jshell> cnf.setMinimumFractionDigits(2)

jshell> cnf.format(123400)
$23 ==> "123.40 thousand"
```

## String.indent(int)
指定した文字数分のインデントを付け加えます。

```sh
jshell> "123\n456".indent(2)
$24 ==> "  123\n  456\n"
```

負の値を指定すると、インデントを減らすことができます。

```sh
jshell> "  123\n 123".indent(-2)
$25 ==> "123\n123\n"
```

Raw String Literalsの名残ですね。
[\[JDK-8200435\] String::align, String::indent - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8200435)

同じくRSLのために入った`align()`はea27には残ってますが、削除コミットがあったのでea28では消えるはずです。
[\[JDK-8215490\] Remove String::align - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8215490)

## String.transform(Function<String, R>)
これもRaw String Literalsの名残ですね。
`String`を受け取って何かを返す関数があるときに、それを適用させるものです。
ただ、これだけでは普通に関数呼び出せばいいんではという感じなんですけど、モチベーションとしては考える順に書けるという感じですね。
[\[JDK-8203703\] String::transform - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8203703)

たとえば、名前を渡せば住所が得れる関数と、住所を渡せばそこの人口が得れる関数があるとします。
ここではMapを。

```sh
jshell> var addresses = Map.of("Mike", "Fukuoka", "John", "Tokyo")
addresses ==> {John=Tokyo, Mike=Fukuoka}

jshell> var population = Map.of("Tokyo", 30000000, "Fukuoka", 2000000)
population ==> {Fukuoka=2000000, Tokyo=30000000}
```

そして、「名前を渡したらその人の住所の人口を表示したい」というとき、こんな感じに書く必要がありました。

```sh
jshell> population.get(addresses.get(name))
$37 ==> 2000000
```
「名前があって住所をとって人口をとる」という処理なのに「人口を返すのに住所を渡すのに名前を渡す」の順に書く必要があります。

これが、`transform`を使うと次のように書けます。

```sh
jshell> name.transform(addresses::get).transform(population::get)
$38 ==> 2000000
```

「名前で住所とって人口とる」という順になってますね。
言語仕様で`関数(値)`を`値→関数`の順に書けるようになってる言語も多いですけど、とりあえずJavaでそれを実現した、って感じですね。
Javaでも`name→address::get→population::get`の順に書けるようになればいいのに。

## Collectors.teeing(Collector, Collector, BiFunction)
ふたつのCollectorの結果を結び付けます。
[\[JDK-8209685\] Create Collector which merges results of two other collectors - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8209685)

たとえば、文字列のリストがあって、空文字列を省いてカンマ区切りにしつつ最終的な要素数も得たい、みたいなときには一回のStream処理では解決できませんでしたが、そういうことができるようになります。

```sh
jshell> Stream.of("aaa", "", "bbb", "ccc").
   ...>   filter(Predicate.not(String::isEmpty)).
   ...>   collect(Collectors.teeing(
   ...>     Collectors.joining(","),
   ...>     Collectors.counting(),
   ...>     Map::entry))
$39 ==> aaa,bbb,ccc=3
```

## Files.mismatch(Path, Path)
ふたつのファイルのうち、最初に異なった位置を返します。同じファイルなら-1
`isSameFile`はありますが、どこが違うかも欲しいんじゃないの？ということで追加されたようです。
[\[JDK-8202302\] (fs) New Files.mismatch method for comparing files - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8202302)

## InputStream.skipNBytes(long)
指定したバイト数、データをスキップします。
[\[JDK-8214072\] InputStream.skipNBytes(long k) to skip exactly k bytes - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8214072)

`skip(long)`があるじゃん、という気がしますが、`skip`は実際に進めた数を返すのに対して、`skipNBytes`は戻り値を返さず、ストリームの終わりを超える値を指定すると`EOFException`を投げます。

```sh
jshell> var input = new ByteArrayInputStream(new byte[5])
input ==> java.io.ByteArrayInputStream@64bf3bbf

jshell> input.skip(2)
$25 ==> 2

jshell> input.skip(4)
$26 ==> 3

jshell> input.reset()

jshell> input.skipNBytes(2)

jshell> input.skipNBytes(4)
|  例外java.io.EOFException
|        at InputStream.skipNBytes (InputStream.java:600)
|        at (#29:1)
```

## CompletableFuture.exceptionallyAsync(Function)
`CompletableFuture`に例外処理をするためのメソッド`exceptionallyAsync`、`exceptionallyCompose`、`exceptionallyComposeAsync`が追加されています。実際には`CompletableStage`インタフェースに追加されたので実装した、という感じ。
[\[JDK-8211010\] Add exception handling methods to CompletionStage and CompletableFuture - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8211010)

すでに`exceptionally`があるけど、compose、async版を追加した、と。

## str.equals("")をstr.isEmpty()に
ぼくでもできる系の変更。こういうリファクタリングもよく入ってます。
[\[JDK-8214971\] Replace use of string.equals("") with isEmpty() - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8214971)

# その他

## Java Flight Recorderツール
jfrコマンドが追加されています。

```sh
$ jfr print --categories GC --events CPULoad recording.jfr
```
などとして使うっぽい
[\[JDK-8205517\] JFR tool - Java Bug System](https://bugs.openjdk.java.net/browse/JDK-8205517)