エンターテイメント!!

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

Java 21の事前調査

モチベ

LTSなので、要調査だと感じている。
そこまでやる気はでなかったけど、なんとか調べた。

公式サイト

JDK 21

環境準備

sdkmanを使って環境準備。
環境準備方法は、過去記事を参照

suzaku-tec.hatenadiary.jp

実際に叩くコマンドは、以下の通り。

sdk install 21.ea.35-open
sdk use java 21.ea.35-open

実験

JEP430

なんか文字列をフォーマットするの、Javaだと面倒だよねてきなことを言っていて、それをなんとかするための提案らしい。

とりあえず、サンプル動かしてみた。
記載されているコードだと、classとかimport見えないので、追記してコンパイル通るようにしておいた。
ちなみに、FormatProcessorのコンストラクタは、privateで隠蔽されているから、createに変えてある。

import java.util.*;

public class Jep430 {

  public static void main(String[] args) {
    Locale thaiLocale = Locale.forLanguageTag("th-TH-u-nu-thai");
    FormatProcessor THAI = FormatProcessor.create(thaiLocale);
    for (int i = 1; i <= 10000; i *= 10) {
        String s = THAI."This answer is %5d\{i}";
        System.out.println(s);
    }
  }
}

実行は、以下の通り

$ javac --enable-preview --release 21 Jep430.java

$ java --enable-preview Jep430
This answer is     ?
This answer is    ??
This answer is   ???
This answer is  ????
This answer is ?????

何やっているかは、よみとけんかった。。。
何かのフォーマットかけているのは分かった。

JEP431

基本データ型について、新規にインタフェースが追加されたっぽい。
とりあえず、公式が載せてるクラス図の画像を載せておく。

https://cr.openjdk.org/~smarks/collections/SequencedCollectionDiagram20220216.png

今まで各要素へのアクセスするやり方は、以下だったはず。

First element Last element
List list.get(0) list.get(list.size() - 1)
Deque deque.getFirst() deque.getLast()
SortedSet sortedSet.first() sortedSet.last()

追加されたインタフェースで、もう少しシンプルにできるようになった。

追加されたものを試す。

import java.util.ArrayList;
import java.util.Arrays;

public class Jep431 {

  public static void main(String[] args) {
    ArrayList<Integer> arrayList = new ArrayList<>();
    arrayList.add(1);
    arrayList.add(2);
    arrayList.add(3);
    arrayList.add(4);
    arrayList.add(5);
    arrayList.addFirst(Integer.valueOf(0));
    arrayList.addLast(Integer.valueOf(6));
    System.out.println("getFirst:" + arrayList.getFirst());
    System.out.println("getLast:" + arrayList.getLast());
    System.out.println(arrayList);
    System.out.println(" --- reversed ---");
    System.out.println(arrayList.reversed());
    System.out.println(" --- remove ---");
    arrayList.removeFirst();
    arrayList.removeLast();
    System.out.println(arrayList);
  }
}

実行結果は、以下の通り。

$ java --enable-preview Jep431
getFirst:0
getLast:6
[0, 1, 2, 3, 4, 5, 6]
 --- reversed ---
[6, 5, 4, 3, 2, 1, 0]
 --- remove ---
[1, 2, 3, 4, 5]

正常に動いてそう。
Listだけだけど、追加されたインタフェースのやつは動いてる。
ただ、Arrays.asListで生成したやつは動かないので注意

JEP440

以前調べたrecordの最終リリース

suzaku-tec.hatenadiary.jp

一時的な入れ物を作るのなら、なんとかなるはず。

JEP441

switch式でパターンマッチングを利用できるようになった。
ただ、switchアンチ民で、使うケースが想像できなんだよな。。。
とりあえず、サンプルコードをもとにサンプル実装してみた。

import java.util.Arrays;

public class Jep441 {

  public static void main(String[] args) {
    System.out.println(formatterPatternSwitch(1));
    System.out.println(formatterPatternSwitch(1L));
    System.out.println(formatterPatternSwitch(1.1));
    System.out.println(formatterPatternSwitch("test"));
    System.out.println(formatterPatternSwitch(Arrays.asList("a", "b", "c")));
  }

  static String formatterPatternSwitch(Object obj) {
    return switch (obj) {
      case Integer i -> String.format("int %d", i);
      case Long l -> String.format("long %d", l);
      case Double d -> String.format("double %f", d);
      case String s -> String.format("String %s", s);
      default -> obj.toString();
    };
  }
}

JEP 452

サンプルをもとに、試し実装。

import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.util.Arrays;

import javax.crypto.SecretKey;
import javax.crypto.KEM;

public class Jep452 {

  public static void main(String[] args) {
    try {
      // Receiver side
      var kpg = KeyPairGenerator.getInstance("X25519");
      var kp = kpg.generateKeyPair();

      // Sender side
      var kem1 = KEM.getInstance("DHKEM");
      var sender = kem1.newEncapsulator(kp.getPublic());
      var encapsulated = sender.encapsulate();
      var k1 = encapsulated.key();
      System.out.println(k1);

      // Receiver side
      var kem2 = KEM.getInstance("DHKEM");
      var receiver = kem2.newDecapsulator(kp.getPrivate());
      var k2 = receiver.decapsulate(encapsulated.encapsulation());
      System.out.println(k2);

      assert Arrays.equals(k1.getEncoded(), k2.getEncoded());
    } catch (Exception e) {
      // TODO: handle exception
    }
  }
}

詳細な内容まとめ

ここで、まずキーペアを作成する。
こいつは、すでにある既存のやつなので、説明は省く

      // Receiver side
      var kpg = KeyPairGenerator.getInstance("X25519");
      var kp = kpg.generateKeyPair();

鍵交換のアルゴリズムを選定。
生成した公開鍵をもとに、キーを作成する。

      // Sender side
      var kem1 = KEM.getInstance("DHKEM");
      var sender = kem1.newEncapsulator(kp.getPublic());
      var encapsulated = sender.encapsulate();
      var k1 = encapsulated.key();

交換アルゴリズム秘密鍵をぶちこんで、インスタンスを生成。
生成したインスタンスと交換用のオブジェクトから、キーを生成する。
この生成したキー(k2)が、送信側で生成したキー(k1)と一致するはず。

      // Receiver side
      var kem2 = KEM.getInstance("DHKEM");
      var receiver = kem2.newDecapsulator(kp.getPrivate());
      var k2 = receiver.decapsulate(encapsulated.encapsulation());

鍵交換を最低限にして、共通キーを交換しているのが利点らしい。
実際の利用方法が想像しにくい。。。
実際に利用すると、処理が分断されて分かりにくくなりそうな気がする。

JEP 453

Concurrency APIを使いやすくするてきなやつらしい。
Concurrency って聞くと、寒気がするので、調べてない。
もう少し、内容が固まったら、調査予定。
初回プレビューだと、情報が少なすぎる。
俺の実力だと調査しきれない。。。
だれか、情報展開をもっとしてくれ(他力本願)

その他雑記+愚痴

JEPに乗ってるコードは、どこまでがサンプルなのか分からなくて、手元で試そうとするとコンパイルエラーになるのが、辛かった。。。
とくにJEP 452がシンドい。
公開鍵の挙動をしらないと、完全に積むだろ、コレ。。。
API読んだり、実装見たりして、コード直しながら毎回試してる気がする。

JEP読むのがハードル高いと思われる原因は、コレでは?って思うの、俺だけ?
サンプルコードがもう少し正確なら、挙動と記載内容から、ある程度理解してもらえると思うんだけどな。。。
英語の壁は、ほとんど感じない。
DeepLで翻訳してるけど、内容はある程度伝わってくるから、技術の進歩はすげぇなぁと思いました(小並感)
どっちかというと、コードの方だよ、問題は。
最初にも書いたけど、書いてあることを見て、コード書くと、コンパイルエラーになるのが、マジで辛たん。。。

参考サイト

Java 21の新機能をざっくりまとめてみた - Qiita

KEM (Java SE 21 & JDK 21)

JDK 21