Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK22 #1397

Merged
merged 1 commit into from
Oct 1, 2024
Merged

JDK22 #1397

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ lede: "JDK 23のリリースを受けてバージョン21~23にかけての変
| 公開日 | 担当者 | タイトル |
|------------|------|----------------------|
| 2024年9月30日 | 金澤祐輔 | [Java 21 新機能紹介](/articles/20240930b/) |
| 2024年10月1日 | 前川喜洋 | Java 22 新機能紹介 |
| 2024年10月1日 | 前川喜洋 | [Java 22 新機能紹介](/articles/20241001a/) |
| 2024年10月2日 | 武田大輝 | Java 23 新機能紹介 |

## さいごに
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: "JDK 21 新機能紹介"
title: "JDK 23 リリース記念連載 | 第1回 JDK 21 新機能紹介"
date: 2024/09/30 00:00:01
postid: b
tag:
Expand Down Expand Up @@ -359,5 +359,4 @@ JDK 21での変更点は[Project Amber](https://openjdk.org/projects/amber/)の
- [JDK 21 (openjdk.org)](https://openjdk.org/projects/jdk/21/)
- [Significant Changes in the JDK (oracle.com)](https://docs.oracle.com/en/java/javase/21/migrate/significant-changes-jdk-release.html#GUID-561005C1-12BB-455C-AD41-00455CAD23A6)

次回は前川さんのJDK 22の紹介記事です。

次回は[前川さんのJDK 22の紹介記事](/articles/20241001a/)です。
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
title: "JDK 23 リリース記念連載 | 第2回 JDK 22 新機能紹介"
date: 2024/10/01 00:00:00
postid: a
tag:
- Java
- JDK22
category:
- Programming
thumbnail: /images/20241001a/thumbnail.png
author: 前川喜洋
lede: "JDK 23のリリースを受けてバージョン21~23にかけての変更点を紹介する連載企画の2本目の記事です。今回はJDK 22でのアップデート内容から正式採用となった以下についてピックアップしてご紹介します。"
---
<img src="/images/20241001a/java22.png" alt="" width="800" height="404">

## はじめに

コアテクノロジーグループの前川です。

[JDK 23のリリースを受けてバージョン21~23にかけての変更点を紹介する連載企画](/articles/20240930a/)の2本目の記事です。

JDK 22でのアップデート内容から正式採用となった以下についてピックアップしてご紹介します。

* [JEP 456: Unnamed Variables & Patterns (無名変数と無名パターン)](https://openjdk.org/jeps/456)
* [JEP 458: Launch Multi-File Source-Code Programs (複数ファイルのソースコードからの起動)](https://openjdk.org/jeps/458)
* [JEP 454: Foreign Function & Memory API (外部機能 & メモリ API)](https://openjdk.org/jeps/454)

これ以外の変更点については[OpenJDKのJDK 22のページ](https://openjdk.org/projects/jdk/22/)や[Oracle JDK Migration Guide](https://docs.oracle.com/en/java/javase/23/migrate/significant-changes-jdk-release.html#GUID-3EE028E1-5DBF-40DE-BDAF-946EFBAF3381)を参照してください。

## JEP 456: Unnamed Variables & Patterns (無名変数と無名パターン)

無名変数(Unnamed Variables)と無名パターン(Unnamed Patterns)は、使用されない変数にフォーカスした新機能です。アンダースコア `_` で表現されます。

### 無名変数

無名変数は、使わない変数を示すために使用されます。

下記の例では、配列や `Optional` オブジェクトの各要素を使用しないことを `_` で明示しています。

```java
for (String _ : new String[]{"A", "B", "C"}) {
// すべての要素もインデックスも無視して”要素の個数分だけ処理を繰り返す”事だけにフォーカスする
}

anyOpt.map(_ -> "foo").orElseGet(() -> "bar"); // anyOpt の内容”の有無”にのみ依存した値を返す
```

### 無名パターン変数

無名パターン変数は、型検査を行う際に特定の型の変数を参照しない場合に使用されます。下記の例では、 `Integer` 型のオブジェクトが無視されます。

```java
switch (obj) {
case String s -> System.out.println("String: " + s);
case Integer _ -> System.out.println("Ignored integer");
default -> System.out.println("Other type");
}
```

### 無名パターン

パターンマッチングの一部で型も省略してワイルドカード的に使用する事も可能です。

```java
class PointNumber<P extends Number> {
final P x;
final P y;
PointNumber(P x, P y) {
this.x = x;
this.y = y;
}
public String toString() { return x + "," + y; }
}

class PointInteger extends PointNumber<Integer>{
PointInteger(Integer x, Integer y) {
super(x, y);
}
}

class PointDouble extends PointNumber<Double>{
PointDouble(Double x, Double y) {
super(x, y);
}
}

record Line(PointNumber<?> start, PointNumber<?> end) {
}

public class App {
public static void main(String[] args) throws Exception {
var line = new Line(new PointInteger(1, 2), new PointDouble(30.0, 40.0));
System.out.println(line);

switch (line) {
case Line(_, PointInteger end) -> System.out.println(end);
case Line(PointInteger start, _) -> System.out.println(start); // 1,2 が出力される
case Line(_, _) -> System.out.println("Unknown type");
}
}
}
```

### 継承/実装したメソッドの未使用引数の明示…には使えない

「基底クラスのメソッドでは受け取る事になっている引数を、このサブクラスでは使用しないよ」と保証する用途に使えそう、と思いきやそうした使用方法はサポートされていません。

```java
public class A implements B{
public void method(int _) { // コンパイルエラー
}
}

interface B {
void method(int x);
}
```

```txt
As of release 22, '_' is only allowed to declare unnamed patterns, local variables, exception parameters or lambda parameters
```

## JEP 458: Launch Multi-File Source-Code Programs (複数ファイルのソースコードからの起動)

Java 11 での機能追加「JEP 330: 単一ファイルのソースコードからの起動」により、main メソッドを持つクラスの単独のソースコードファイルをコンパイルすること無く java コマンドで実行できるようになりました。

```java Main.java
public class HelloWorld { // JEP 330/458により起動されるソースファイルの場合、publicクラス名とファイル名が一致している必要は無い
public static void main(String[] args) {
System.out.println(HelloWorld.class.getName());
}
}
```

```bash
$ java Main.java
HelloWorld
```

JEP 458 では java コマンドの引数に指定されたソースファイルから参照されているソースファイルも順次コンパイルされて実行できるようになりました。

```java Main.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println(Clazz.class.getName());
}
}
```

```java Clazz.java
public class Clazz {
}

```

```bash
$ java Main.java
Clazz
```

JEP 330 からの注意すべき変更として一点、java コマンド実行時のソースファイルまでのパス(の終端)と package 文とが整合している事が要求されるようになりました。

```java src/Main.java
package main;
```

```bash
$ java src/Main.java
エラー: ソース・ファイルへのパスの終わりがパッケージ名mainと一致しません: src/Main.java
```

## JEP 454: Foreign Function & Memory API (外部機能 & メモリ API)

JNIに代わりJVM外のライブラリの関数をJavaから呼び出すことができるAPIと、ヒープ外のメモリにアクセスするAPIのセットです。 `java.lang.foreign` パッケージを使用します。

```java
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.SymbolLookup;
import java.lang.invoke.MethodHandle;

public class FFM {
public static void main(String[] args) throws Throwable {
Linker linker = Linker.nativeLinker();

// アリーナ内でメモリを確保する。Arena#close の呼出しによりメモリは解放される。
try (Arena arena = Arena.ofConfined()) {
// OS依存でライブラリのルックアップ方法が変わり、Windowsでは anyLibrary.dll というDLLファイルは anyLibrary という名前でもロード可能。
SymbolLookup lib = SymbolLookup.libraryLookup("libhello_ffm.so", arena);
// 戻り値 void, 引数無しの hello 関数を取得する
MethodHandle hello = linker.downcallHandle(
lib.find("hello").orElseThrow(),
FunctionDescriptor.ofVoid());
// 実行
hello.invokeExact();
}
}
}
```

Java側のコーディング方法以外でのJNIからの大きな変更点として以下の作業が不要になりました。

* `javac -h` でJNI用のヘッダファイルを作成
* 呼び出されるライブラリ側の実装で `JNIEXPORT` などを使用してJNI向けに関数を公開

## おわりに

Preview や Incubator の変更点も含めると他にも色々ありますが、ここで取り上げた物を振り返ると「普段はあまり多用しないものの、いざ必要となった時の手順が煩雑であった点」が改善され、シンプルに使えるようになったように思います。

次回は武田さんのJDK 23のご紹介になります。
Empty file.
Binary file added source/images/20241001a/java22.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added source/images/20241001a/thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading