エンターテイメント!!

遊戯王好きのJavaエンジニアのブログ。バーニングソウルを会得する特訓中。

Java22リリース内容調査

環境準備

sdkmanを利用しているので、下記のコマンドで実行

sdk install java 22-open
sdk use java 22-open

インストール確認を下記です。

$ java -version
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
openjdk version "22" 2024-03-19
OpenJDK Runtime Environment (build 22+36-2370)
OpenJDK 64-Bit Server VM (build 22+36-2370, mixed mode, sharing)

検証

検証のために作ったコードは、下記の自分のGithubにコミットしてある。

GitHub - suzaku-tec/Java22Sample: Java22 Sample code

JEP

  • 423: Region Pinning for G1
  • 447: Statements before super(...) (Preview)
  • 454: Foreign Function & Memory API
  • 456: Unnamed Variables & Patterns
  • 457: Class-File API (Preview)
  • 458: Launch Multi-File Source-Code Programs
  • 459: String Templates (Second Preview)
  • 460: Vector API (Seventh Incubator)
  • 461: Stream Gatherers (Preview)
  • 462: Structured Concurrency (Second Preview)
  • 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)
  • 464: Scoped Values (Second Preview)

423: Region Pinning for G1

サマリーの日本語文

Javaネイティブ・インタフェース(JNI)のクリティカル領域でガベージ・コレクションを無効にする必要がないように、G1に領域ピンニングを実装することで待ち時間を短縮する。

コメント

あんまりGCは詳しくないんだよね。。。
JNIはたまに使うけど、それのメモリ回収が効率化したって認識でいる。

447: Statements before super(...) (Preview)

サマリーの日本語文

Javaプログラミング言語のコンストラクタで、生成されるインスタンスを参照しないステートメントを、明示的なコンストラクタ呼び出しの前に表示できるようにする。これはプレビュー言語の機能です。

検証

まずは、今までの実装

import java.math.BigDecimal;

public class JEP447 extends BigDecimal {

    public JEP447(long value) {
        super(value);               // Potentially unnecessary work
        if (value <= 0)
            throw new IllegalArgumentException("non-positive value");
    }

}

super()より先に実装することは出来ない。
これを、以下に変更する。

import java.math.BigDecimal;

public class JEP447 extends BigDecimal {

    public JEP447(long value) {
        if (value <= 0)
            throw new IllegalArgumentException("non-positive value");

        super(value);               // Potentially unnecessary work
    }

}

今までのコンパイルだと、下記のようなエラーになる。

$ javac JEP447.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
PositiveBigDecimal.java:9: エラー: superの呼出しはコンストラクタの先頭文である必要があります
        super(value);               // Potentially unnecessary work

下記コマンドで、Java22のプレビュー機能を利用してやると、コンパイルに成功する。

$ javac --enable-preview --release 22 JEP447.java 
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
ノート: PositiveBigDecimal.javaはJava SE 22のプレビュー機能を使用します。
ノート: 詳細は、-Xlint:previewオプションを指定して再コンパイルしてください。

変わったのは、こういうことらしい。

コメント

この変更で開発者が受けるメリットは、super()呼び出す前に、値の検証ができるってことらしい。
継承先で新たなチェックを付与したいときに、実装が楽になる感じ。
今までだと、たぶん super(check(xxx)) みたいにして、メソッド噛ませていたのが、なくなるのだろうと思う。

個人的には、コンストラクタの時点でチェックすることがほぼなかったので、あまり気にはならないが、継承関連で混乱する開発者がでてきそうな気がしないでもない。
処理順序について、明確にしておく必要があるなと感じた。

454: Foreign Function & Memory API

サマリーの日本語文

JavaプログラムがJavaランタイム外のコードやデータと相互運用できるAPIを導入する。外来関数(すなわち、JVM外のコード)を効率的に呼び出し、外来メモリ(すなわち、JVMによって管理されていないメモリ)に安全にアクセスすることによって、APIは、Javaプログラムが、JNIのもろさや危険性なしに、ネイティブ・ライブラリを呼び出し、ネイティブ・データを処理することを可能にする。

コメント

検証するのがかなり面倒だから、検証はスキップ。
JNI書けるような人は、たぶん、JEPの記事読めば分かるだろうとは思う。
自分も、C++で作られたライブラリをJavaで連携する際にJNI書いたことあるけど、かなり厄介だった思い出が。。。
いづれ試してみたいが、個人的には優先度低め。
今だと、Rustのライブラリが多いのだろうか?

456: Unnamed Variables & Patterns

サマリーの日本語文

無名変数と無名パターンは、Javaプログラミング言語を強化するもので、 変数宣言やネストされたパターンが必要だが使われない場合に使用できる。どちらもアンダースコア文字 _ で示されます。

検証

以下、サンプルを下に自分が用意した実装

import java.util.Arrays;

public class JEP456 {

  public static void main(String[] args) {
    int total = count(Arrays.asList(new Order(), new Order(), new Order()));
    System.out.println(total);
  }

  static int count(Iterable<Order> orders) {
    int total = 0;
    for (Order _ : orders)    // Unnamed variable
        total++;
    return total;
  }

}

class Order {}

注目するのは、for分の _ 利用している箇所。
Java21でプレビュー機能を有効にせずにコンパイルするとコンパイルエラーになる。
Java22では、問題なくコンパイル可能。
他にも例あったけど、面倒くさいので省略。

コメント

おそらく、宣言したけど、使わない変数の代価のために用意されたのだろう。
結構レアケースだとは思うが、場合によっては、解析ツールで警告されたりするから、それ回避するためだったりするのだろうか?
今までにない言語仕様なので、使い所がまだパッと思いつかない。
たぶん、使える箇所はあると思われるから、知識として覚えておきたい。

457: Class-File API (Preview)

サマリーの日本語文

Javaクラスファイルを解析、生成、変換するための標準APIを提供する。これはプレビューAPIです

検証

やっていることは、HellWorld.classを作り、"Hello World"を表示するだけ。
サンプルコードがネットに散らばってたけど、コンパイルに失敗するのばかりで、調査に時間がかかった。。。

import java.lang.classfile.ClassFile;
import static java.lang.classfile.ClassFile.*;
import java.lang.constant.ClassDesc;
import java.nio.file.Path;
import java.io.IOException;
import java.lang.constant.MethodTypeDesc;

public class JEP457 {

  public static void main(String[] args) throws IOException {
    ClassFile helloWorldClass = ClassFile.of();
    helloWorldClass.buildTo(Path.of("HelloWorld.class"), ClassDesc.of("HelloWorld"), classBuilder -> {
      classBuilder.withMethodBody("main", MethodTypeDesc.ofDescriptor("([Ljava/lang/String;)V"), ACC_PUBLIC | ACC_STATIC, codeBuilder -> {
        codeBuilder.getstatic(ClassDesc.of("java.lang.System"), "out", ClassDesc.of("java.io.PrintStream"))
          .ldc("Hello World")
          .invokevirtual(ClassDesc.of("java.io.PrintStream"), "println", MethodTypeDesc.ofDescriptor("(Ljava/lang/Object;)V"))
          .return_();
      });
    });
  }

}

上記をコンパイルして実行すると、HelloWorld.classができる。

$ javac --enable-preview --release 22 JEP457.java
$ java --enable-preview JEP457

さらに、作られたHelloWorld.javaを実行すると、下記のような出力がされる。

$ java HelloWorld
Hello World

コメント

これ、classファイルの作りを理解してないと、作るの難しい。。。
ただ、作れると、JavaAPIで提供されてない動的な処理をやらせることができるのだろうと感じた。そうとうレアな要求が無い限り、普通に開発するだけだったら、絶対に使わないと思う。

458: Launch Multi-File Source-Code Programs

サマリーの日本語文

Javaアプリケーション・ランチャーを強化し、Javaソースコードの複数ファイルとして提供されるプログラムを実行できるようにする。これにより、小規模なプログラムから大規模なプログラムへの移行がより緩やかになり、開発者はビルド・ツールの設定に手間をかけるかどうか、またそのタイミングを選択できるようになる。

コメント

ビルド系のものなのでスルー

459: String Templates (Second Preview)

以前調べたのでスルー

460: Vector API (Seventh Incubator)

前提知識が必要そうだし、試験導入なのでスルー

461: Stream Gatherers (Preview)

サマリーの日本語文

Stream APIを強化し、カスタム中間操作をサポートする。これにより、ストリーム・パイプラインは、既存の組み込み中間操作では容易に実現できない方法でデータを変換できるようになる。これはプレビューAPIです。

検証

立ち位置的に、Collectorsっぽい

import java.util.stream.*;
import java.util.*;

public class JEP461 {
  public static void main(String[] args) {
    // will contain: [[1, 2, 3], [4, 5, 6], [7, 8]]
    List<List<Integer>> windows =
      Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowFixed(3)).toList();
    System.out.println(windows);
  }
}

コンパイルして実行すると、下記の通り

$ javac --enable-preview --release 22 JEP461.java 
$ java --enable-preview JEP461
[[1, 2, 3], [4, 5, 6], [7, 8]]

コメント

Collectorsとの棲み分けをどうするんだろう?って思ってる。
まだ、利用用途がハッキリ理解できてないから、混同しているのかもしれない。
おそらく、機械学習とかで使うのだろうか?配列操作系の処理があると、Pythonっぽく見える。

462: Structured Concurrency (Second Preview)

セカンドプレビューなのでスキップ

463: Implicitly Declared Classes and Instance Main Methods (Second Preview)

セカンドプレビューなのでスキップ

464: Scoped Values (Second Preview)

セカンドプレビューなのでスキップ

所感・感想・雑記

本当なら、リリース前に調べるはずだったのに。。。
すっかり頭から抜けていたな。
Googleカレンダーに予定入れておくべきだったかもしれない。

調べるの、辛かった。。。
特に辛いのは、サンプルコードが動かなかったとき。
JEP457が、特に苦行だった。。。

何しているのか分からないところから調べるのが、一番辛い。
ただ、概要は理解できたはず。

LTS後だから、あんまりリリース内容がないかと思ったが、結構多かった。

Gatherers が一番利用頻度たかそう。
最後は力尽きた感が。。。

参考リンク

JDK 22

Oracle、「Java 22」を発表(窓の杜) - Yahoo!ニュース

オラクル、「Java 22」をリリース(クラウド Watch) - Yahoo!ニュース

Java in the Box Annex: JEPでは語れないJava 22

JEP 457 Hello World | Dr James Hamilton

Java 22新機能まとめ #Java - Qiita