106
77

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Java 25新機能まとめ

Last updated at Posted at 2025-09-16

Java 25が2025/9/16にリリースされました。
Java 25 / JDK 25: General Availability
Oracle Releases Java 25
The Arrival of Java 25

LTSで、Java 21からの変更も多いので、長く使われるバージョンになると思います。
今回はmainメソッドの簡略化モジュール単位でのimportが正式化されたことが大きいですね。というか、それ以外は大きな影響がなさそうです。
IO.printlnと書けるようになったことは、補完が効かない環境でコードを書くときにいいです。
あとSoundClipは雑ゲームを作るときに便利。

JDKをインストールせずに言語やライブラリの新機能を試したい場合にはJava Playgroundが便利です。
https://dev.java/playground/

Samplesに新機能のサンプルがあります。
image.png

イベント

新機能解説のイベントを福岡で開催します。
10/17(金)に福岡エンジニアカフェで19時から行います。
Java 25リリースイベント@福岡 - connpass

資料

詳細はこちら
JDK 25 Release Notes
Java SE 25 Platform JSR 400
OpenJDK JDK 25 GA Release

APIドキュメントはこちら
Overview (Java SE 25 & JDK 25)

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

APIの差分はこちら。
https://cr.openjdk.org/~iris/se/25/build/latest/java-se--jdk-24-ga--jdk-25%2B36/

ディストリビューション

MacやLinuxでのインストールにはSDKMAN!をお勧めします。

Oracle OpenJDK以外に無償で商用利用できるディストリビューションとしては、次のようなものがあります。

※ Microsoftは未リリース

どのディストリビューションを使えばいいかわからないときは、とりあえずEclipse Temurinが無難です。
アップデートは10月に25.0.1が、1月に25.0.2がリリースされることになります。
Oracle JDKの無償ライセンスであるNFTCは次期LTSまで有効で、それ以降のアップデートでは有償のOTNに切り替わるので注意が必要です。

開発組織

関わった開発組織は、こんな感じになってます。比率は大きくないですが、日本企業ではFujitsuとNTT Dataが貢献を続けています。

Untitled.png

JEP

大きめの変更はJEPでまとまっています。
https://openjdk.org/projects/jdk/25/

今回は18個のJEPが取り込まれました。正式採用は12個です。プレビューからの正式化はScoped ValuesとModule Import Declarations、Compact Source Files、Flexible Constructor Bodiesの4つで、後者3つによってコードが書きやすくなっています。プレビューは6個で、そのうち3つが新たに入ったものです。

今回は次の5つのカテゴリにまとめてます

470: PEM Encodings of Cryptographic Objects (Preview)
502: Stable Values (Preview)
503: Remove the 32-bit x86 Port
505: Structured Concurrency (Fifth Preview)
506: Scoped Values
507: Primitive Types in Patterns, instanceof, and switch (Third Preview)
508: Vector API (Tenth Incubator)
509: JFR CPU-Time Profiling (Experimental)
510: Key Derivation Function API
511: Module Import Declarations
512: Compact Source Files and Instance Main Methods
513: Flexible Constructor Bodies
514: Ahead-of-Time Command-Line Ergonomics
515: Ahead-of-Time Method Profiling
518: JFR Cooperative Sampling
519: Compact Object Headers
520: JFR Method Timing & Tracing
521: Generational Shenandoah

18個というのは、半年リリースになって以降としては、前回の24個についで多いですね。
前回LTSのJava 21でその前のJava 17からのJEP数が37個だったことを考えると、今回はJava 21から66個のJEPが取り込まれているので、結構な機能改善がされていることになります。ただし、同じ内容のJEPがpreviewとして何度も入っているので、その分は差し引く必要があります。
Untitled.png

言語機能

言語機能の変更としては新しいものはないですが、いままでPreviewだった機能が正式化されています。

507: Primitive Types in Patterns, instanceof, and switch (Third Preview)
511: Module Import Declarations
512: Compact Source Files and Instance Main Methods
513: Flexible Constructor Bodies

507: Primitive Types in Patterns, instanceof, and switch (Third Preview)

Java 23でプレビューとして入りましたが、変更なく3rdプレビューになりました。

instanceof

instanceofでプリミティブを使うとき、値が欠落しないかどうかが判定基準になります。

jshell> int i = 128
i ==> 128

jshell> i instanceof byte
$2 ==> false

jshell> i = 127
i ==> 127

jshell> i instanceof byte
$4 ==> true

実数型を整数型で判定するときは、精度落ちするかどうかが判定されます。

jshell> double d = 1
d ==> 1.0

jshell> d instanceof int
$2 ==> true

jshell> d = 1.2
d ==> 1.2

jshell> d instanceof int
$4 ==> false

ただし、ラッパークラスのオブジェクトの場合はその基本型のときだけtrueになります。

jshell> Long num = 123L
num ==> 123

jshell> num instanceof int
|  エラー:
|  不適合な型: java.lang.Longをintに変換できません:
|  num instanceof int
|  ^-^

jshell> num instanceof long
$7 ==> true

そしてパターンマッチとして使えるわけですね。

jshell> long num = 123
num ==> 123

jshell> var out = new ByteArrayOutputStream()
out ==>

jshell> if (num instanceof byte b) out.write(b)

jshell> out.toByteArray()
$21 ==> byte[1] { 123 }

jshell> num = 1234
num ==> 1234

jshell> if (num instanceof byte b) out.write(b)

jshell> out.toByteArray()
$24 ==> byte[1] { 123 }

switch

このパターンマッチがswitchでも使えるということなんですけど、定数パターンもあるので、switchですべての型が使えるようになったということになります。

jshell> long num = 1234
num ==> 1234

jshell> switch (num) { case int n -> "いんと"; default -> "それ以外";}
$25 ==> "いんと"

jshell> num = 30_0000_0000L
num ==> 3000000000

jshell> switch (num) { case int n -> "いんと"; default -> "それ以外";}
$27 ==> "それ以外"

if式のようなこともできますね。

boolean flag = isFoo();
var s = switch (flag) {
  case true -> "たった";
  case false -> "おりた";
}

511: Module Import Declarations

Java 23でプレビューとして入り、Java 25で正式化されました。

モジュールごとのimportができるようになっています。java.baseをimportしたらだいたいいけるってなりそうです。あと、外部ライブラリのモジュール対応が進みそうです。

Java 23のときからの変更で、依存のあるモジュールもimportされるようになりました。そのためjava.seをimportすると、Java SEのすべてのAPIがimportされます。

次のようにすると、java.baseモジュールに属するjava.utilもjava.ioもimportされることになります。

import module java.base;

JShellでもデフォルトでjava.baseがimportされるようになります。
例えば、java.timeはimportされていなかったのでLocalDateをそのまま使うとエラーになります。

>jshell
|  JShellへようこそ -- バージョン24
|  概要については、次を入力してください: /help intro

jshell> LocalDate.now()
|  エラー:
|  シンボルを見つけられません
|    シンボル:   変数 LocalDate
|    場所: クラス
|  LocalDate.now()
|  ^-------^

Java 25ではimportなしでLocalDateが使えます。

>jshell
|  JShellへようこそ -- バージョン25
|  概要については、次を入力してください: /help intro

jshell> LocalDate.now()
$1 ==> 2025-09-16

SwingでGUIプログラムをする場合にはjava.desktopモジュールをimportします。

jshell> import module java.desktop;

jshell> var f = new JFrame("hello")
f ==> javax.swing.JFrame[frame0,0,0,0x0,invalid,hidden, ... tPaneCheckingEnabled=true]

jshell> var b = new JButton("OK")
b ==> javax.swing.JButton[,0,0,0x0,invalid,alignmentX=0 ... xt=OK,defaultCapable=true]

ただ、そうするとListjava.util.Listjava.awt.Listでかぶるので、あいまいになってそのままで使えなくなります。

jshell> List a = null;
|  エラー:
|  Listの参照はあいまいです
|    java.awtのクラス java.awt.Listとjava.utilのインタフェース java.util.Listの両方が一致します
|  List a = null;
|  ^--^

この場合にはjava.util.Listなど実際に使うほうをimportするなどが必要です。

jshell> import java.util.List

jshell> List a = null
a ==> null

512: Compact Source Files and Instance Main Methods

Java 24で4thプレビューになっていたSimple Source Files and Instance Main MethodsがCompact Souce Files...と名前を変えて正式化されました。こういった仕様名のこだわりもいいですね。

パブリックスタティックヴォイドメインの呪文から解放されるやつです。
Javaがパブリックスタティックヴォイドメインの呪文から解放される - きしだのHatena

Javaでは単純なハローワールドを書くために次のようなコードが必要でした。

public class Hello {
  public static void main(String[] args) {
    System.out.println("Hello Java!");
  }
}

これが次のように書けるようになります。

void main() {
  IO.println("Hello Java!");
}

publicclassstaticなどのキーワードが消え、[]という謎の記号も消えました。
プログラムを勉強するときに、まずやりたいことは処理を書くことです。
クラスは書いた処理をうまく構成するための仕組みなので、処理が書けないうちに勉強してもあまり意味がありません。
publicなどアクセス指定はプログラムが大きくなったときに不適切な要素を使ってしまわないための仕組みなので、入門時のサンプルでは不要です。
staticを説明するにはクラスやインスタンスの理解が必要になりますが、処理が書ける前に勉強するには早すぎます。
配列も変数を知らないうちに勉強できるものでもなく、入門時のサンプルで引数argsを使うことはあまりありません。
その結果「よくわからないしきたり」のまま放置されがち、というか放置せざるを得ない状態で「System.out.pritlnというのは~」という説明をすることになりますが、クラス名とファイル名が違うので動かせなくてハマってそこまでたどりつけなかったりもします。

ということで、初期に学習するべきことに集中できるようにするために、次のように制約が緩和されました。

  • クラスの定義が不要になる
  • mainメソッドはインスタンスメソッドでよくなる
  • mainメソッドの引数を省略できる
  • mainメソッドがpublicじゃなくてもよくなる

「メソッドも不要でいいのでは?」となると思いますが、現状ではステートメントとメソッドを同レベルで書く仕組みがないため、新たにローカルメソッドのような仕組みが必要になり、「初期に学習するべきことに集中できるようにするため」としては影響範囲が大きいので残されています。

このあたりは、次のデザインノートにまとめられています。
https://openjdk.org/projects/amber/design-notes/on-ramp

mainメソッドはインスタンスメソッドでもよくなる

mainメソッドにstaticをつけなくてもよくなります。そして、mainメソッドにstaticをつけなくてもいいということは、そこから呼び出すメソッドなどにもstaticをつけなくていいということになるので、少し大きめのサンプルが書きやすくもなります。

public class Hello {
  public void main(String[] args) {
    foo();
  }
  void foo() {
    IO.println("Hello");
  }
}

mainメソッドの引数を省略できる / mainメソッドがpublicじゃなくてもよくなる

書かなくてよさそうなものを書かずにすむのですっきりします。
mainメソッドをprivateにすることはできません。protectedは可能です。
「public static void main(String[] args)」を何も見ずに書けるようになったときにJavaに馴染んだ満足感があったので、それがなくなるのは寂しいですが、単なるノスタルジーなのでなくていいと思います。

クラスの定義が不要

クラスを知らなくていいことの他に、クラス名を考えなくていいとかインデントが一段浅くなるとか、中カッコが一組だけになるので間違いが減るとか、いろいろ入門がやりやすくなります。

void main() {
  IO.println("Hello Java");
}

クラスを省略してmainメソッドにインスタンスメソッドを使うとき、Java 24でのプレビューまではnew Object(){}で囲まれることになっていましたが、正式リリースのJava 25でこの仕様は削られています。

new Object() {
  void main() {
    IO.println("Hello Java");
  }
}.main();

現状では、ファイル名と同じクラスが定義されてそのメンバになるようです。

クラス定義を省略する場合、ファイル名にstatic.javaなどキーワードを付けるとエラーになります。クラス定義がある場合、javaコマンドで直接実行であれば問題ないです。

>java static.java
static.java:3: エラー: 不正なファイル名: static
  void main() {
  ^
エラー1個
エラー: コンパイルが失敗しました

java.baseがmodule importされる

暗黙のクラスを使う場合、java.baseモジュールもimportされます。
こういうコードはimportなしで書けるようになります。

void main() {
 var data = List.of("test", "data");
 IO.println(data.stream().collect(Collectors.joining(" ")));
}

513: Flexible Constructor Bodies

Java 22でStatements before superだったものがJava 23で名前が変わり、大きな変更なくJava 25で正式化しました。

スーパークラスのコンストラクタ呼び出しの前にthisを使わないステートメントが書けるようになります。

例えばListを2つコンストラクタにとるクラスがあるとします。

class Foo {
  Foo(List l1, List l2) {
  }
}

このコンストラクタを継承するとき、Listをふたつ渡す必要があります。

class Bar extends Foo {
  Bar() {
    super(List.of("abc", "def"), List.of("abc", "def"));
  }
}

同じものを渡しているので共通化したいですが、superの前でステートメントを実行できないので迂回を考える必要があります。

class Bar extends Foo {
  private Bar(List l) {
    super(l, l);
  }
  Bar() {
    this(List.of("abc", "def"));
  }
}

これを、次のように書けるようになります。

class Bar extends Foo {
  Bar() {
    var param = List.of("abc", "def");
    super(param, param);
  }

このように、パラメータの検証や構築、共有がある場合に、自然なコードで書けるようになります。
次のようなフィールドのアクセスをsuperの前に行うとエラーになります。

class Bar extends Foo {
  List<String> param;
  Bar() {
    param = List.of("abc", "def");
    super(param, param);
  }
}
test.java:11: エラー: スーパータイプのコンストラクタの呼出し前はparamを参照できません
    param = List.of("abc", "def");
    ^

API

APIの変更としてはセキュリティ系を除いて4つのJEPがありますが、新しく入ったのはStable Valueです。Scoped Valueが正式化されています。またJEPになっていない変更が結構あります。

502: Stable Values (Preview)
505: Structured Concurrency (Fifth Preview)
506: Scoped Values
508: Vector API (Tenth Incubator)

小さいもの

JEPになっていないAPI変更で、動きがわかりやすいものを挙げます。

java.lang.IO

java.lang.IOというクラスが導入されました。このクラスには、printprintlnreadlnの3つのstaticメソッドが定義されています。
これを利用してSystem.out.printlnではなくIO.printlnを使って次のようにHello worldが書けます。

void main() {
  IO.println("Hello");
}

static importを行えば、printlnだけで文字列出力ができます。

import static java.lang.IO.*;
void main() {
  println("Hello");
}

JShellやメモ帳など、soutのような補完の効かない環境でのコード入力に特に便利です。
また、System.ioInputStreamを返していたため、入力操作にはIOExceptionへの対処が必要になっていましたが、IO.readlnではIOErrorを投げるため例外処理を省略できます。

javax.sound.SoundClip

次のようにしてWAVファイルを再生できます。

var file = new File("sound.wav");
var clip = SoundClip.createSoundClip(file);
clip.play();

いままで、音声ファイルを再生する一番手軽な手段はApplet APIのAudioClipだったのですが、Applet APIはJava 17でDeprecated になり、Java 26で削除の予定です。

そこで手軽に音声を再生するための代替手段として、SoundClipクラスが導入されました。
[JDK-8356049] Need a simple way to play back a sound clip - Java Bug System

標準では非圧縮PCMにしか対応していないので、MP3を再生するにはSPIを導入する必要があります。
Java 25でMP3を再生する - きしだのHatena

ゲーム効果音に使うときの注意点はこちら。
Java 25のSoundClipでゲームに効果音をつける - きしだのHatena

Reader.readAllLines / readAllAsString

ReaderクラスにList<String>を返すreadAllLinesStringを返すreadAllAsStringのふたつのメソッドが追加されました。

public List<String> readAllLines() throws IOException
public String readAllAsString() throws IOException

[JDK-8354724] Methods in java.io.Reader to read all characters and all lines - Java Bug System

CharSequence.getChars(int, int, char[], int)

文字列を文字単位で処理するときに、範囲指定で一括してchar配列に取り込むメソッドが用意されました。

Reader.ofの実装を簡素化することが目的のようですが、同様に文字列を文字単位で処理する場合に効率がよくなるようです。

[JDK-8343110] Add getChars(int, int, char[], int) to CharSequence and CharBuffer - Java Bug System

BodyHandlers.limiting / BodySubscribers.limiting

HttpClientでの送受信データをBodyHandler / BodySubscriberで処理をするときに上限バイト数を指定しやすくなります。

次のようにすると、250バイトだけ文字列として取得するということになります。

client.send(request, BodyHandlers.limiting(BodyHandlers.ofString(), 250))

[JDK-8328919] Add BodyHandlers / BodySubscribers methods to handle excessive server input - Java Bug System

ForkJoinPoolのScheduledFuture対応

ForkJoinPoolScheduledFuture対応のメソッドが追加されました。

  • cancelDelayedTasksOnShutdown()
  • getDelayedTaskCount
  • schedule(Runnable, long, TimeUnit)
  • schedule(Callable, long, TimeUnit)
  • scheduleAtFixedRate(Runnable, long, long, TimeUnit)
  • scheduleWithFixedDelay(Runnable, long, long, TimeUnit)
  • submitWithTimeout(Callable, long, TimeUnit, Consumer)

[JDK-8319447] Improve performance of delayed task handling - Java Bug System

StrictMath

毎回StrictMathにちょっとずつメソッドが追加されていますが、今回も7つのメソッドが追加されました。

  • powExact(int, int)
  • powExact(long, int)
  • unsignedMultiplyExact(int, int)
  • unsignedMultiplyExact(long, int)
  • unsignedMultiplyExact(long, long)
  • unsignedPowExact(int, int)
  • unsignedPowExact(long, int)

502: Stable Values (Preview)

Javaでは、不変な値を保持する仕組みとしてfinalがあります。

final Logger logger = Logger.create();

しかし、クラスやインスタンスの初期化時にすべての不変値を初期化してしまうと、起動が遅くなったりネットやファイルへのアクセスが集中することにもなります。
そこで、値が必要になったときに初期化したいということが多くあります。
そのような場合、アクセッサを介して値を得るようにすることで、遅延初期化を実現します。

private Logger logger;
Logger getLogger() {
  if (logger == null) {
    Logger.create();
  }
  return logger;
}

けれども、このようにするとフィールドからfinalが外れることでJVMでの最適化が効きにくくなります。また、マルチスレッドを考慮すると少し複雑なコードが必要になります。もしくは、マルチスレッドで初期化が多重に行われても問題ないかどうか判断して、実質的な問題がなければそのままスレッドセーフではないコードを使うことになります。

そういった場合に使えるのが今回導入されるStableValueです。

private final StableValue<Logger> logger = StableValue.of();
Logger getLogger() {
  return logger.orElseSet(() -> Logger.create());
}

このときorElseSetに指定した初期化コードは1度だけしか呼び出されないことがStableValueによって保証され、スレッドセーフになります。また、JVMでの最適化も行われるようになります。

アクセッサメソッドの定義が面倒ということもあります。その場合はsupplierが使えます。

final Supplier<Logger> logger = StableValue.supplier(() -> Logger.create());

不変値の集合を扱いたいときはlistが使えます。

final List<Connection> pool = StableValue.list(10, idx -> new Connection(idx + "th connection");

こうするとpool.get(3)などとしてリストにアクセスすると、初回にそのインデックスに対応する値が初期化されるようになります。

StableValueはプレビューなので、使うときには--enable-previewが必要です。

505: Structured Concurrency (Fifth Preview)

Java 19でIncubatorとして含まれていましたが、Java 24で4th Previewになり、Java 25ではStructuredTaskScopeがクラスからインタフェースになり、openファクトリメソッドを使ってインスタンスを得るようになりつつ5thプレビューになりました。

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

Response handle() throws InterruptedException {
    try (var scope = StructuredTaskScope.open()) {
        Subtask<String>  user  = scope.fork(() -> findUser());
        Subtask<Integer> order = scope.fork(() -> fetchOrder());

        scope.join()            // Join both forks, propagatiton exceptions

        // Both subtasks have succeeded, so compose their results
        return new Response(user.get(), order.get());
    }
}

SubtaskSupplierを継承しているので、Supplierとして扱うほうがいいかもしれません。

506: Scoped Values

Java 20でIncubateになりJava 21でプレビュー、Java 24からはScopedValue.orElseでnullを受け付けなくなって正式化しました。

同じスレッド内で値を共有したいときThreadLocalを使いますが、値の変更が可能であったり子スレッドに値が引き継がれたり少し重いので、より限定された仕組みを提供する、ということのようです。
つまり、値を引数でひっぱりまわすのは面倒なのでグローバル変数的にstaticフィールドを使いたい程度のモチベーションで値を共有化するときに、スレッドセーフのためのThreadLocalは重すぎる、という感じですね。
たとえば次のような処理があります。

void start() {
  proc1("test");
}

void proc1(String str) {
  IO.println(str);
  proc2(str);
}

void proc2(String str) {
  IO.println(str);
}

これを、全部のメソッドにいちいち引数を設定して値をひきまわるのは面倒なのでフィールドを使おう、という場合。

String str;

void start() {
  str = "test";
  proc1();
}

void proc1() {
  IO.println(str);
  proc2();
}

void proc2() {
  IO.println(str);
}

これは複数スレッドから呼び出されると正しく動かないことがあります。
スレッドセーフにするためにThreadLocalを使っていました。

final ThreadLocal<String> VAR = new ThreadLocal<>();

void start() {
  VAR.set("test");
  proc1();
}

void proc1() {
  IO.println(VAR.get());
  proc2();
}

void proc2() {
  IO.println(VAR.get());
}

しかし、引数を書いて値を持ちまわっていくのめんどいね、くらいのモチベーションで使うにはThreadLocalは重過ぎるので、軽量な値共有手段としてScopedValueが導入されます。

final ScopedValue<String> VAR = new ScopedValue<>();

void start() {
  ScopedValue.where(VAR, "test")
    .run(() -> proc1());
}

void proc1() {
  IO.println(VAR.get());
  proc2();
}

void proc2() {
  IO.println(VAR.get());
}

508: Vector API (Tenth Incubator)

AVX命令のような、複数のデータに対する計算を同時に行う命令をJavaから利用できるようになります。
使うためには実行時やコンパイル時に--add-modules jdk.incubator.vectorをつける必要があります。

Java 16でインキュベータとして導入されたPanamaプロジェクトの残る片割れですが、Java 24から実装の変更などが入って10th Incubatorになりました。Project Valhallaのvalue classを使いたいようで、関連JEPがpreviewになるまではIncubatorのままということです。

基本的な使い方は次のようになります。

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()               castShape(               check(
compare(                 compress(                convert(
convertShape(            div(                     elementSize()
elementType()            eq(                      equals(
expand(                  fma(                     getClass()
hashCode()               intoArray(               intoMemorySegment(
lane(                    lanewise(                length()
lt(                      maskAll(                 max(
min(                     mul(                     neg()
notify()                 notifyAll()              pow(
rearrange(               reduceLanes(             reduceLanesToLong(
reinterpretAsBytes()     reinterpretAsDoubles()   reinterpretAsFloats()
reinterpretAsInts()      reinterpretAsLongs()     reinterpretAsShorts()
reinterpretShape(        selectFrom(              shape()
slice(                   species()                sqrt()
sub(                     test(                    toArray()
toDoubleArray()          toIntArray()             toLongArray()
toShuffle()              toString()               unslice(
viewAsFloatingLanes()    viewAsIntegralLanes()    wait(
withLane(  

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

JVM

JVMの変更として、セキュリティ関連以外では5つJEPが導入されています。

503: Remove the 32-bit x86 Port
514: Ahead-of-Time Command-Line Ergonomics
515: Ahead-of-Time Method Profiling
519: Compact Object Headers
521: Generational Shenandoah

503: Remove the 32-bit x86 Port

Java 24ではWindows用の32-bit x86コードが削除されていました。
479: Remove the Windows 32-bit x86 Port

また、他のプラットフォーム向けの32-bit x86は非推奨にされています。
JEP 501: Deprecate the 32-bit x86 Port for Removal

ということで、今回はコードが消されることになりました。
Arm用の32bitコードは残るはず。Raspberry Piで使われているので。

514: Ahead-of-Time Command-Line Ergonomics

Java 24で取り込まれたJEP 483: Ahead-of-Time Class Loading & Linkingでクラスのローディングデータを使いまわすことでの起動時間短縮が可能になりました。
けども、この際のコマンドラインオプションが結構めんどくさい。

まず記録。

java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf \
       -cp app.jar com.example.App ...

それからキャッシュファイルの作成

java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf \
       -XX:AOTCache=app.aot -cp app.jar

そして実行時にキャッシュを利用です。

java -XX:AOTCache=app.aot -cp app.jar com.example.App ...

この、準備に使う最初の2つが統合されて、次のように書けるようになります。

java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ...

515: Ahead-of-Time Method Profiling

JEP 483では、クラスデータをキャッシュして使いまわせるようにしていましたが、メソッドプロファイルデータも同時に使いまわせるようにしてピークパフォーマンスまでの時間を短縮します。
特別なコマンドオプションは導入されていません。

519: Compact Object Headers

JVM内でオブジェクトを保持するときに、64bitプラットフォームでは、96-128bit、つまり12-16バイトをヘッダとして使っているのですが、これを64bit、8バイトにするものです。
このことによってヒープサイズは減り、データの局所性があがります。キャッシュに乗りやすくなって性能があがるということですね。

現在はデフォルトで無効で、-XX:+UseCompactObjectHeadersというVMオプションをつけることで有効化されます。Java 24で必要だった-XX:+UnlockExperimentalVMOptionsは正式化により不要になりました。
今後、デフォルト有効にしたあと、現在の96-128bitヘッダに関するコードを削除する方向です。

521: Generational Shenandoah

Java 24で試験導入されていたShenandoah GCでの世代別GCが正式化しました。

Security

セキュリティ、暗号関係では次の2つのJEPが導入されています。

470: PEM Encodings of Cryptographic Objects (Preview)
510: Key Derivation Function API

470: PEM Encodings of Cryptographic Objects (Preview)

暗号鍵や証明書などの暗号オブジェクトを送受信するための表現形式として、Privacy-Enhanced Mail(PEM)形式がよく使われています。PEM形式は名前のとおり、メール用に設計されましたが、他の用途にも使われるようになっています。
このJEPで、PEM形式へのエンコードやデコードを行うAPIを定義します。

510: Key Derivation Function API

暗号鍵を安全に生成するためのキー導出機能(KDF)のAPIです。
Java 21でJEP 452 として導入されたKey Encapsulation Mechanism(KEM)で、公開鍵暗号のもとで安全に共有鍵を交換する仕組みが導入されました。それにあわせて、今回のKDFの導入で、ハイブリッド公開鍵暗号の実装の準備が整います。

ハイブリッド公開鍵暗号では、短いセッション鍵を一旦生成してKEMでカプセル化して送信、共有されたセッション鍵を使ってお互いにKDFで対照鍵を生成してデータ交換に利用、という流れになります。

ツール

ツール関連ではJVM Flight Recorder関連の変更が3つ入っています。

509: JFR CPU-Time Profiling (Experimental)
518: JFR Cooperative Sampling
520: JFR Method Timing & Tracing

509: JFR CPU-Time Profiling (Experimental)

Linux環境でカーネルのCPUタイマーを使うことで、CPU時間プロファイリングが行えるようにします。
Linux専用の機能になりますが、将来的に他の環境にも対応する予定です。
サンプリング結果はjdk.CPUTimeSampleイベントとして記録されます。

次のようにして有効にします。

$ java -XX:StartFlightRecording=jdk.CPUTimeSample#enabled=true,filename=

518: JFR Cooperative Sampling

JDK Flight Recoderでは、数ミリ秒ごとといった固定間隔で実行スタックをサンプリングすることでプロファイルを行っています。
そのため、JFRのサンプラースレッドは、対象スレッドを一時停止してスタックフレームを解析します。JDKではスタックフレームを補助するメタデータを提供しますが、これはセーフポイントと呼ばれる位置で停止した場合に限られます。かといって、セーフポイントだけでスタックフレームの解析を行うと、頻繁に実行されるコードがセーフポイント付近にない場合に精度が落ちるセーフポイントバイアス問題が発生します。
そういった問題が発生しないよう非同期にサンプリングを行うと、セーフポイント以外で停止した場合には非効率であったりJVMがクラッシュすることもあります。

このJEPでは、サンプリング機構を設計しなおしてセーフポイントのみでサンプリングを行うようにしています。セーフポイントバイアスの問題を回避するために、サンプリングタイミングではプログラムカウンタとスタックポインタをサンプル要求としてキューに記録し、次にセーフポイントに到達したときにスタックフレームの解析を行うことで、安全でバイアスなくサンプリングが行われるようにします。

520: JFR Method Timing & Tracing

JDK Flight Recoderにjdk.MethodTimingjdk.MethodTraceの2種類のイベントを導入して、メソッドの時間やトレースを記録できるようにします。

106
77
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
106
77

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?