Java 19新機能まとめ

Java 19が2022/9/20にリリースされました。

https://mail.openjdk.org/pipermail/jdk-dev/2022-September/006933.html
今回、正式導入された機能がほとんどありませんが、Record PatternsやVirtual Threadは注目すべき機能です。

こちらの配信で解説しています。
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228058/1601b660-d2f8-36f7-1cba-f852930261e1.png)](https://www.youtube.com/watch?v=-5zlmBnxmCU)

詳細はこちら
[JDK 19 Release Notes](https://jdk.java.net/19/release-notes)
[Java SE 19 Platform JSR 394](https://openjdk.java.net/projects/jdk/19/spec/)
[OpenJDK JDK 19 GA Release](https://jdk.java.net/19/)

APIドキュメントはこちら
[Overview (Java SE 19 & JDK 19)](https://docs.oracle.com/en/java/javase/19/docs/api/index.html)

追加されたAPIまとめはこちら
https://docs.oracle.com/en/java/javase/19/docs/api/new-list.html

APIの差分はこちら。
https://cr.openjdk.java.net/~iris/se/19/latestSpec/apidiffs/overview-summary.html

MacやLinuxでのインストールには[SDKMAN!](https://sdkman.io/)をお勧めします

Oracle OpenJDK以外に無償で商用利用できるディストリビューションとしては、次のようなものがあります。
(Java 20が出たためダウンロードリンクがなくなっているものもあります)
<!--
(まだ用意されていないものもあります。9/22時点ではOracle JDK, Azul Zulu, Corretto 19, SapMachineがダウンロード可能です)
-->

- [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) ※対外サーバーの運用には有償ライセンスが必要です
- [Adoptium Temurin](https://adoptium.net/?variant=openjdk19&jvmVariant=hotspot)
- [Azul Zulu](https://www.azul.com/downloads/?version=java-19-sts&package=jdk)
- [Liberica JDK](https://bell-sw.com/pages/downloads/#/java-19-current)
- [Amazon Corretto 19](https://docs.aws.amazon.com/corretto/latest/corretto-19-ug/downloads-list.html)
- [Microsoft Build of OpenJDK](https://www.microsoft.com/openjdk)
- [SapMachine](https://sap.github.io/SapMachine/)

アップデートは10月に19.0.1が、1月に19.0.2がリリースされることになります。

# JEP
大きめの変更はJEPでまとまっています。
https://openjdk.java.net/projects/jdk/19/

今回は7個のJEPが取り込まれました。すでにプレビューなどで出ていたものが3つあり、新たに取り込まれたものは4です。ただし、正式に取り込まれたのは1つだけです。
また、今回は削除された機能、非推奨になった大きな機能というのはありません。

[JEP 405: Record Patterns (Preview)](https://openjdk.java.net/jeps/405)
[JEP 422: Linux/RISC-V Port](https://openjdk.java.net/jeps/422)
[JEP 424: Foreign Function & Memory API (Preview)](https://openjdk.java.net/jeps/424)
[JEP 425: Virtual Threads (Preview)](https://openjdk.java.net/jeps/425)
[JEP 426: Vector API (Fourth Incubator)](https://openjdk.java.net/jeps/426)
[JEP 427: Pattern Matching for switch (Third Preview)](https://openjdk.java.net/jeps/427)
[JEP 428: Structured Concurrency (Incubator)](https://openjdk.java.net/jeps/428)

# ツール
今回ツール関係の変更はありませんでした。

# 言語機能

言語機能の変更としては、Record Patternsがプレビューとして入りました。また、Pattern Matching for switchが3rdプレビューになっています。

[JEP 405: Record Patterns (Preview)](https://openjdk.java.net/jeps/405)
[JEP 427: Pattern Matching for switch (Third Preview)](https://openjdk.java.net/jeps/427)

## [JEP 405: Record Patterns (Preview)](https://openjdk.java.net/jeps/405)

レコードの分解ができるパターンマッチです。
たとえばPointというレコードを用意します。
```
jshell> record Point(int x, int y) {}
|  次を作成しました: レコード Point

jshell> var p = new Point(3, 5)
p ==> Point[x=3, y=5]
```

そうすると次のようなパターンが書けます。

```
jshell> p instanceof Point(var xx, var yy)
$3 ==> true
```

条件式と組み合わせて、パターンマッチが成り立つ時にそのまま変数の値を扱うことができます。

```
jshell> p instanceof Point(var xx, var yy) ?
   ...>   "x:%d y:%d".formatted(xx, yy) :
   ...>   "no match"
$4 ==> "x:3 y:5"
```

固定値の指定は出来なさそう。

```
jshell> p instanceof Point(3, var yy)
|  エラー:
|  型の開始が不正です
|  p instanceof Point(3, var yy)
|                     ^
```

Pointを持つBoxを定義します。

```
jshell> record Box(Point topLeft, Point bottomRight){}
|  次を作成しました: レコード Box

jshell> var b = new Box(new Point(3, 4), new Point(7, 9))
b ==> Box[topLeft=Point[x=3, y=4], bottomRight=Point[x=7, y=9]]
```

そうすると、Box内のPointの値を直接取り出すことができます。

```
jshell> b instanceof Box(Point(var left, var top), Point(var right, var bottom)) ?
   ...>   "(%d, %d)-(%d, %d)".formatted(left, top, right, bottom) : "no match"
$8 ==> "(3, 4)-(7, 9)"
```

次のように命令的にレコードの中身を得ていくよりも、やりたいことがはっきりします。

```
b instanceof Box b ?
  "(%d, %d)-(%d, %d)".formatted(b.topLeft().x(), b.topLeft().y(), 
                                b.bottomRight().x(), b.bottomRight().y()) : 
  "no match"
```

## [JEP 427: Pattern Matching for switch (Third Preview)](https://openjdk.java.net/jeps/427)

パターンマッチが`switch`で使えるようになります。
3rdプレビューになりました。今回大きな変更がなければ、きっとJava 20で正式機能になりそうです。
Java 19では、使うときに`--enable-preview`が必要です。

「といってもパターンマッチってそんなに出番ないのでは？」
と思うかもしれませんが、大きな影響が。

`switch`で`case null`が書けるようになります。

```
jshell> String s = null
s ==> null

jshell> switch (s) {
   ...>     case "test" -> "テスト";
   ...>     case null -> "ぬるぽ";
   ...>     default -> "hello";
   ...> }
$13 ==> "ぬるぽ"
```

`case null`がない場合は従来どおりNullPointerExceptionです。

```
jshell> switch (s) {
   ...>     case "test" -> "テスト";
   ...>     default -> "hello";
   ...> }
|  例外java.lang.NullPointerException: Cannot invoke "String.hashCode()" because "<local0>" is null
|        at (#12:1)
```

`""`と`null`で同じ処理を行う場合などに併記できるのが便利です。

```
jshell> switch(s){
   ...>     case null, "" -> "empty";
   ...>     default -> s;
   ...> }
$17 ==> "empty"
```

`default`と`null`で同じ処理したいときにアロースタイルで書けないんでは？という疑問に応えて、`default`が`case`に書けるようになっています。

```
jshell> switch (s) {
   ...>     case "one" -> 1;
   ...>     case "two" -> 2;
   ...>     case null, default -> -1;
   ...> }
$21 ==> -1
```

で、パターンマッチですが、型と変数をswtichに書けるようになりました。これをタイプパターンといいます。

```
jshell> Object o = "abc"
o ==> "abc"

jshell> switch (o) {
   ...>     case String s -> "--%s--".formatted(s);
   ...>     case Integer i -> "%03d".formatted(i);
   ...>     default -> o.toString();
   ...> }
$35 ==> "--abc--"
```

タイプパターンのあとに`when`でつなげて条件を書くことでガード節とすることができます。

```
jshell> o = "helo"
o ==> "helo"

jshell> switch (o) {
   ...>     case String s when s.length() < 5 -> "--%s--".formatted(s);
   ...>     case String s -> s.toUpperCase();
   ...>     case Integer i -> "%05d".formatted(i);
   ...>     default -> o.toString();
   ...> }
$42 ==> "--helo--"
```

2ndプレビューでは`when`ではなく`&&`を使っていました。
```
switch (o) {
    case String s && s.length() < 5 -> "--%s--".formatted(s);
    case String s -> s.toUpperCase();
    case Integer i -> "%05d".formatted(i);
    default -> o.toString();
}
```


定数パターンとタイプパターンをひとつのswitchで使うこともできます。定数パターンに使えるのはこれまでどおり整数、文字列、enumです。

```
jshell> s = "helo"
s ==> "helo"

jshell> switch (s) {
   ...>     case "test" -> "テスト";
   ...>     case String s when s.length() < 5 -> s.toUpperCase();
   ...>     default -> "too long";
   ...> }
$29 ==> "HELO"
```

case句のタイプパターンで定義した変数のスコープは、case句の中だけです。
ここでは`switch`の外にあるのと同じく変数`s`を定義してcase句で上書きしていますが、switchの外に影響はありません。

```
jshell> s = "helo"
s ==> "helo"

jshell> switch (s) {
   ...>     case String s when s.length() < 5 -> (s="Hello").toUpperCase();
   ...>     default -> "too long";
   ...> }
$30 ==> "HELLO"

jshell> s
s ==> "helo"
```

Record Patternsと併用が本命ですね。

```
return switch(n) {
    case IntExpr(int i) -> i;
    case NegExpr(Expr n) -> -eval(n);
    case AddExpr(Expr left, Expr right) -> eval(left) + eval(right);
    case MulExpr(Expr left, Expr right) -> eval(left) * eval(right);
    default -> throw new IllegalArgumentException(n);
};
```

ここでSealed Classと組み合わせて次のような定義になっているとします。

```
sealed interface Expression
  permits IntExpr, NegExpr, AddExpr, MulExpr {}
record IntExpr(int i) implements Expression {}
record NegExpr(Expr n) implements Expression {}
record AddExpr(Expr left, Expr right) implements Expression {}
record MulExpr(Expr left, Expr right) implements Expression {}
```

そうすると、Expressionが取りうるのが４つのレコードで全てということがわかるのでdefault句が不要になります。また、全てをチェックしていることを保証できるのが、既存のコードと違うところで、パターンマッチのメリットです。

```
Expression n = getExp();
return switch(n) {
    case IntExpr(int i) -> i;
    case NegExpr(Expr n) -> -eval(n);
    case AddExpr(Expr left, Expr right) -> eval(left) + eval(right);
    case MulExpr(Expr left, Expr right) -> eval(left) * eval(right);
};
```

# API

[JEP 424: Foreign Function & Memory API (Preview)](https://openjdk.java.net/jeps/424)
[JEP 425: Virtual Threads (Preview)](https://openjdk.java.net/jeps/425)
[JEP 426: Vector API (Fourth Incubator)](https://openjdk.java.net/jeps/426)
[JEP 428: Structured Concurrency (Incubator)](https://openjdk.java.net/jeps/428)

## 小さいもの

### BigDecimal.TWO

これが正式機能で唯一多くの人が喜ぶ機能追加かもしれない・・・

```
jshell> BigDecimal.TWO
$1 ==> 2
```

### Thread.sleep(Duration)

sleepメソッドにDurationが指定できるようになったので、よりわかりやすく書けるようになりました。

```
jshell> Thread.sleep(Duration.ofSeconds(3))
```

`sleep(3000)` じゃ どんだけ待つか、仕様を知らないとわからないし、仕様を知っていても直観的じゃないですよね。

### Localeのコンストラクタがdeprecatedに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228058/e52f6222-86cf-c3e7-cd94-c31aacc06a7b.png)

代わりに`of`メソッドを使います。

```
jshell> Locale.of("ja")
$12 ==> ja

jshell> Locale.of("ja","jp")
$13 ==> ja_JP
```

### HashMap / HashSet / LinkedHashMap / LinkedHashSet newXxx

容量を指定してオブジェクトを生成する newHashMapなどのstaticメソッドがそれぞれ追加されています。

```
jshell> Map<String, String> m = HashMap.newHashMap(10)
m ==> {}
```

`new HashMap(10)`との違いは、`<>`がなくても「無検査変換」って出ないことと、指定した数ぴったりの容量ではなく、指定した数の要素を格納するのに十分な容量になる、ということかな。

```
jshell> Map<String, String> m = new HashMap(10)
|  警告:
|  無検査変換
|    期待値: java.util.Map<java.lang.String,java.lang.String>
|    検出値:    java.util.HashMap
|  Map<String, String> m = new HashMap(10);
|                          ^-------------^
m ==> {}
```


### Double.PRECISION / Float.PRECISION

有効数字の精度bit数です。

```
jshell> Double.PRECISION
$2 ==> 53

jshell> Float.PRECISION
$3 ==> 24
```

### Math.TAU

半径に対する円周比です。つまり2π。

```
jshell> Math.TAU
$4 ==> 6.283185307179586

jshell> Math.TAU / 2
$5 ==> 3.141592653589793

jshell> Math.PI
$6 ==> 3.141592653589793
```

### Integer.compress, expand / Long.compress, expand

commpressが第一引数に指定した数値について第二引数で指定したbitだけ取り出して右に詰めます。  
 
```
jshell> Integer.toHexString(Integer.compress(0xcafebabe, 0xf000f0f0))
$15 ==> "cbb"
```

expandは逆で、第一引数に指定した数値の下位bitを第二引数で指定したbitに広げます。 

```
jshell> Integer.toHexString(Integer.expand(0xcbb, 0xf000f0f0))
$16 ==> "c000b0b0"
```

## [JEP 425: Virtual Threads (Preview)](https://openjdk.java.net/jeps/425)

仮想スレッドです。いままでJavaは、初期にプラットフォームスレッドを使うようになって以来、ずっとThreadとしてプラットフォームスレッドを使ってきました。
プラットフォームスレッドというのは、OSが管理するようなスレッドです。OSが管理するスレッドというのは、YouTubeで動画を見てTwitterして時計を表示してファイナルファンタジーやって、と何でも同時に動かせるように設計されています。
もちろんアプリケーションの中でいろいろな働きのスレッドを動かすのですが、多くのスレッドを立ち上げることになるのは、結局同じことをするスレッドです。
その中で、計算のために同じことをするというのはハードウェアの構成を考えないといけなくて、そのための構成がGPUだったりVector APIで扱うSIMD命令だったりするわけですね。
そして、アプリケーションの処理としては結局のところ計算の時間よりも通信待ちの時間のほうがはるかに長いということで、通信待ち時間を有効利用したいというのが並列処理の主な目的になっていました。
そうすると、計算の最中にバランスとりながら処理を切り替えるプラットフォームスレッドというのはオーバークオリティだったわけで、やりたいことに対してメモリも食うし限界も低いし遅いということになってたわけです。
ということで、現状でJavaではReactiveやRxといって通信のときに他の処理に制御を渡せるようなコードを書いているのですが、これが非常に難しくてやってられないということで、Javaから離れてKotlinのように自然にそういう処理が書ける言語に移行する人がでています。

という問題に対処するために、OSではなくJVMが管理するスレッドがVirtual Threadとして導入されます。Virtual ThreadはProject Loomで開発されていました。

Virtual Threadは既存のプラットフォームスレッドと同様に扱うことができるよう気をつけてAPIが設計されています。

ただ、プラットフォームスレッドでは`new Thread()`としてスレッドを生成できましたが、コンストラクタでVirtual Threadを生成することはできません。

いままでのプラットフォームスレッドはこんな感じで使いました。

```
jshell> Thread t = new Thread(() -> System.out.println("hello"))
t ==> Thread[#220496,Thread-110304,5,main]

jshell> t.getState()
$33 ==> NEW

jshell> t.start()

jshell> hello

jshell> t.getState()
$35 ==> TERMINATED
```

Java 19ではThread.Builderが用意されて、`ofPlatform`か`ofVirtual`でプラットフォームスレッドと仮想スレッドを分けれるようになります。
`unstarted`メソッドを使うと、`new Thread`と同様にまだ開始していないスレッドを得れます。

```
jshell> Thread t = Thread.ofPlatform().unstarted(() -> System.out.println("hello"))
t ==> Thread[#220491,Thread-110303,5,main]

jshell> t.start()

hello
jshell> t.getState()
$24 ==> TERMINATED
```

そして`ofVirtual`に変更すると仮想スレッドを得れます。仮想スレッドはThreadクラスのオブジェクトとして扱えます。使い方はプラットフォームスレッドと同様です。

```
jshell> Thread t = Thread.ofVirtual().unstarted(() -> System.out.println("hello"))
t ==> VirtualThread[#220492]/new

jshell> t.start()

jshell> hello

jshell> t.getState()
$27 ==> TERMINATED
```

`start`メソッドを使うと、スレッドの実行と`Thread`オブジェクトの取得が同時に行えます。
```
jshell> Thread t = Thread.ofVirtual().start(() -> System.out.println("hello"))
t ==> VirtualThread[#220497]/runnable
hello

jshell> t.getState()
$37 ==> TERMINATED
```

`ExecutorService`で仮想スレッドを使う場合は、`Executors.newVirtualThreadPerTaskExecutor`を使います。

```
jshell> ExecutorService ex = Executors.newVirtualThreadPerTaskExecutor()
ex ==> java.util.concurrent.ThreadPerTaskExecutor@28ba21f3
jshell> ex.submit(() -> System.out.println("hello"))
$40 ==> java.util.concurrent.ThreadPerTaskExecutor$ThreadBoundFuture@64a294a6[Not completed]
hello

jshell> ex.isTerminated()
$41 ==> false

jshell> ex.isShutdown()
$42 ==> false

jshell> ex.shutdown()
jshell> ex.isTerminated()
$44 ==> true

jshell> ex.isShutdown()
$45 ==> true
```

では、少し性能を見てみましょう。
3秒待つメソッドを定義しておきます。

```
jshell> import java.time.Duration

jshell> void s(){ try{ Thread.sleep(Duration.ofSeconds(3));} catch(Exception ex){}}
|  次を作成しました: メソッド s()
```

プラットフォームスレッドを100起動してそれぞれで3秒待ちます。

```
jshell> IntStream.range(0, 100).forEach(i -> Thread.ofPlatform().start(() -> s()))
```

スレッドが100増えてすぐ元にもどっていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228058/55fab284-3451-0d10-524c-b392df11662d.png)

仮想スレッドを100起動してそれぞれで3秒待ちます。

```
jshell> IntStream.range(0, 100).forEach(i -> Thread.ofVirtual().start(() -> s()))
```

そうすると、17スレッドだけ増えて31スレッドになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228058/d115960e-0ccd-7913-ffbb-3d748cb5ef24.png)

100増えないことと、終わってもスレッドが残っていることがわかります。

それでは10万スレッドを同時に実行してみましょう。
まずは仮想スレッドから。

```
jshell> IntStream.range(0, 100_000).forEach(i -> Thread.ofVirtual().start(() -> s()))
```

10:09のところで実行しています。スレッド数は31のまま、CPU使用率は7%くらいです。メモリは120MBくらい使っていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228058/2d56b0c4-ef8b-7b11-4e3d-e0173ef3d509.png)

プラットフォームスレッドで試してみます。

```
jshell> IntStream.range(0, 100_000).forEach(i -> Thread.ofPlatform().start(() -> s()))
```

まず、しばらく処理が終わりません。
スレッドは2万弱くらいまで使われていますが、その2万弱のスレッドでスレッドが終わったら別のスレッドというふうにやりくりして10万スレッドを処理できるまで、繰り返されます。
また、CPUは80%近くまで使われています。処理はSleepするだけなので、スレッド切り替えにCPUを使っていると推測されます。メモリはそれほど使っていませんね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228058/5a2f35a3-bb1a-aa18-c15e-520f700e9901.png)

このように、多数のスレッドを処理するときにプラットフォームスレッドでは同時処理数に限界があることと、CPUパワーを余分に使ってしまうので、軽量な仮想スレッドが求められ実装されたわけです。

## [JEP 428: Structured Concurrency (Incubator)](https://openjdk.java.net/jeps/428)

並列処理では、複数の処理を実行するときに、両方が終われば正常終了とか、どちらか片方が終われば終了だとか、どちらか一方でも例外が発生したら終了だとか、同時に行う処理で連動することがあります。
しかし、これを既存の`join`や`wait`などで制御しようとすると、実際には`join`から`wait`へのGo Toを書くようなコードになって、処理が追えなくなります。
そこで導入されるのが構造化並列性といいます。
こんな感じ。詳しくはあとで書きます！

```
Response handle() throws ExecutionException, InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        Future<String>  user  = scope.fork(() -> findUser());
        Future<Integer> order = scope.fork(() -> fetchOrder());

        scope.join();           // Join both forks
        scope.throwIfFailed();  // ... and propagate errors

        // Here, both forks have succeeded, so compose their results
        return new Response(user.resultNow(), order.resultNow());
    }
}
```

## [JEP 426: Vector API (Fourth Incubator)](https://openjdk.java.net/jeps/426)

AVX命令のような、複数のデータに対する計算を同時に行う命令をJavaから利用できるようになります。
Project Panamaのひとつとして開発されていました。
Java 16でインキュベータとして導入されましたが、今回4thインキュベータになりました。

使うためには実行時やコンパイル時に`--add-modules jdk.incubator.vector`をつける必要があります。

```java
import jdk.incubator.vector.*;
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;

void vectorComputation(float[] a, float[] b, float[] c) {

    for (int i = 0; i < a.length; i += SPECIES.length()) { // SPECIES.length() = 256bit / 32bit -> 8
        VectorMask<Float> m = SPECIES.indexInRange(i, a.length); // 端数がマスクされる
                                                                 // a.lengthが11でiが8のとき最初の3つしか要素がないので [TTT.....]
		// FloatVector va, vb, vc;
        FloatVector va = FloatVector.fromArray(SPECIES, a, i, m);
        FloatVector vb = FloatVector.fromArray(SPECIES, b, i, m);
        FloatVector vc = va.mul(va).
                    add(vb.mul(vb)).
                    neg();
        vc.intoArray(c, i, m);
    }
}
```

利用できるのは次の6つの型です。それぞれに対応するVector型があって、これが基本になります。

|型|bit幅|Vector|
|--|--|--|
|byte|8|ByteVector|
|short|16|ShortVector|
|int|32|IntVector|
|long|64|LongVector|
|float|32|FloatVector|
|double|64|DoubleVector|

ただ、利用するにはVectorSpeciesが必要です。利用したいVectorにSPECIES_\*という定数が用意されているので、それを使います。\*は一度に計算するbit数ですね。

```
jshell> FloatVector.SP
SPECIES_128         SPECIES_256         SPECIES_512         SPECIES_64          SPECIES_MAX         SPECIES_PREFERRED   
```

MAXではそのハードウェアで使える最大、PREFERREDは推奨ビット数だけど、同じになるんじゃないのかな。ここでは256bitが推奨されて、floatが8個同時に計算できるようになっていますね。

```
jshell> FloatVector.SPECIES_PREFERRED
$11 ==> Species[float, 8, S_256_BIT]
```

ハードウェアで使えるbit数は搭載CPUに依存しますが、普通のIntel/AMDであれば256、XEONとか つよつよCPUなら512かな。M1は128でした。ハードウェアでサポートされないbit数を使おうとするとソフトウェア処理になるので遅くなります。

実際のVectorはfrom*というメソッドで取得します。fromArray、fromByteArray、fromByteBufferが用意されています。インキュベータに入る前はfromValuesがあったのですが、なくなってますね。

Vectorを得られたら、用意されたメソッドで計算します。ひととおりの算術命令はあります。

```
jshell> va.
abs()                   add(                    addIndex(               bitSize()               blend(                  
broadcast(              byteSize()              compare(                div(                    elementSize()           
elementType()           eq(                     equals(                 fma(                    getClass()              
hashCode()              intoArray(              intoByteArray(          intoByteBuffer(         lane(                   
lanewise(               length()                lt(                     max(                    min(                    
mul(                    neg()                   notify()                notifyAll()             pow(                    
rearrange(              reduceLanes(            reduceLanesToLong(      reinterpretAsBytes()    reinterpretShape(       
selectFrom(             shape()                 slice(                  sqrt()                  sub(                    
test(                   toArray()               toDoubleArray()         toIntArray()            toLongArray()           
toShuffle()             toString()              unslice(                viewAsFloatingLanes()   viewAsIntegralLanes()   
wait(                   withLane(      
```

ところで、こういったメソッド呼び出しの内部でAVX命令などを呼び出すのでは遅くなるんではという気がしますが、実際にはJVM intrinsicsという仕組みでJITコンパイラがこれらのメソッド呼び出しをネイティブ関数呼び出しに置き換えます。


## [JEP 424: Foreign Function & Memory API (Preview)](https://openjdk.java.net/jeps/424)

3rdインキュベータではなくPreviewになりましたが、Foreign Function APIの前身であるForeign Linker APIはJava 16から、Foreign Memory APIはJava 14からインキュベータで、結構ながくインキュベータやってます。なので もう番号ふるのをやめたのかな

### Foreign Memory API
ヒープ外のメモリをアクセスする方法としては、ByteBufferを使う方法やUnsafeを使う方法、JNIを使う方法がありますが、それぞれ一長一短があります。
ByteBufferでdirect bufferを使う場合、intで扱える範囲の2GBまでに制限されたり、メモリの解放がGCに依存したりします。
Unsafeの場合は、性能もいいのですが、名前が示すとおり安全ではなく、解放済みのメモリにアクセスすればJVMがクラッシュします。
JNIを使うとCコードを書く必要があり、性能もよくないです。

ということで、ヒープ外のメモリを直接扱うAPIがJava 14でインキュベータモジュールとして導入され、今回6バージョン目のインキュベータです。
次のようなコードになります。

```java
import java.lang.foreign.*;
import java.nio.ByteOrder;

VarHandle intHandle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());

try (MemorySegment segment = MemorySegment.allocateNative(100)) {
   for (int i = 0 ; i < 25 ; i++) {
        intHandle.set(seg, i * 4, i);
   }
}
```

コンパイル、実行では`--enable-preview`を付ける必要があります。

MemoryHandlesからwithOffsetとwithStrideが消えましたね。

```
jshell> import java.lang.foreign.*

jshell> MemoryHandles.
asAddressVarHandle(   asUnsigned(           class                 collectCoordinates(   dropCoordinates(
filterCoordinates(    filterValue(          insertCoordinates(    permuteCoordinates(   varHandle(
```

Java 15ではMemoryHandlesからVarHandleを得るメソッドが拡充してました。

```
jshell> MemoryHandles.
asAddressVarHandle(   asUnsigned(           class                 collectCoordinates(   dropCoordinates(
filterCoordinates(    filterValue(          insertCoordinates(    permuteCoordinates(   varHandle(
withOffset(           withStride(
```

Java 14では次の3つのメソッドしかありませんでした。

```
jshell> MemoryHandles.
class         varHandle(    withOffset(   withStride(
```

Java 16ではMemoryAccessというユーティリティが用意されて、VarHandleを使わずにシンプルにかけるようになっています。

```java
import java.lang.foreign.*;

try (MemorySegment segment = MemorySegment.allocateNative(100)) {
   for (int i = 0 ; i < 25 ; i++) {
        MemoryAccess.setIntAtOffset(i * 4, i);
   }
}
```

### Foreign Function API
ネイティブライブラリの呼び出しを行う。
外部メモリのアクセスにはForeign Memory Access APIを使う
JNIの代替

Java 16でForeign Linkerとして1stインキュベータになり、今回4バージョン目のインキュベータです。

たとえばこんな感じのC関数があって。

```
size_t strlen(const char *s);
```

こんな感じで`MethodHandle`を取り出して。

```
CLinker linker = CLinker.systemCLinker();
MethodHandle strlen = linker.downcallHandle(
    linker.lookup("strlen").get(),
    FunctionDescriptor.of(JAVA_LONG, ADDRESS)
);
```

こんな感じで呼び出すようです。

```
MemorySegment cString = implicitAllocator().allocateUtf8String("Hello");
long len          = strlen.invoke(cString);  // 5
```

# JDK

JDKの変更、つまりリリース方針などの変更としては、今回RISC-Vへの対応が入りました。

## [JEP 422: Linux/RISC-V Port](https://openjdk.java.net/jeps/422)

対応したのはSIMD命令付64bitのRV64GVコンフィグレーションです。
まだVector APIにはちゃんと対応してないぽい。
[[vectorIntrinsics] Vector API for RISC-V](https://mail.openjdk.org/pipermail/panama-dev/2022-September/017669.html)