Java 23の新機能12個のJEPと現在地|サポート終了後の移行判断
Java 23は2024年9月17日にGA(一般提供開始)となった非LTSリリースで、12個のJEPを含みます。非LTSの提供期間は6か月と決まっているため、2026年8月時点ではOracleのPremier Supportがすでに終了しており、新規に選ぶ対象ではありません。それでも「Java 23」を調べる価値が残るのは、この版で先行公開されたプレビュー機能の多くが、Java 24・25・26で正式機能として着地しているからです。最新版の内容は2026年3月リリースのJava 26で開発者が押さえるべき10個のJEPと全体像で扱っています。本記事はJava 23そのものに絞り、12個のJEPが今どうなったかを一次情報とJDK 23.0.2での実行結果で整理します。
まとめ:Java 23の要点
Java 23の要点は5つです。第一に、プレビューでもインキュベーターでもなく確定したのはMarkdownドキュメンテーションコメント(JEP 467)、ZGCの世代別モード既定化(JEP 474)、sun.misc.Unsafeのメモリアクセスメソッド非推奨化(JEP 471)の3つだけで、残る9つは試験段階のまま出荷されました。第二に、その9つのうち6つはJava 25までに正式化され、プリミティブ型パターン・構造化並行性・Vector APIの3つは2026年8月時点でも試験段階が続いています。第三に、Java 21・22でプレビューだったString TemplatesがJava 23で取り下げられており、22から23への移行ではコンパイルエラーという形で影響が出ました。第四に、Oracle Java SE Support RoadmapはJava 23を含む22〜24の非LTSについてExtended Supportを「Not Available」と明記しており、延命の選択肢がありません。第五に、Java 23で警告付きのまま残せた-XX:-ZGenerational指定は、Java 24以降は無視されます。以下、それぞれの根拠と実際の挙動を見ていきます。
Java 23の位置づけとサポート終了状況
Java 23はJava SE 23のリファレンス実装として2024年9月17日にGAを迎えました。半年ごとのリリースサイクルにおける非LTS版で、後継のJava 24は2025年3月18日、Java 25 LTSは2025年9月16日、Java 26は2026年3月17日にGAとなっています。OpenJDKの更新も早期に打ち切られており、Eclipse Temurinで配布されているJava 23の最終アセットはjdk-23.0.2+7、バージョン文字列はopenjdk version "23.0.2" 2025-01-21です。2025年1月のセキュリティ更新以降、Java 23向けの新しいビルドは出ていません。
Oracle Java SE Support Roadmapの記載
Oracleが公開しているサポートロードマップでは、Java 23は「22 – 24 (non-LTS)」の行にまとめて記載されています。この行のPremier SupportはGAの6か月後までで、Extended Supportの欄は「Not Available」です。LTS版と比べると差が明確です。
| リリース | 区分 | GA | Premier Support | Extended Support |
|---|---|---|---|---|
| Java 17 | LTS | 2021年9月 | 2026年9月 | 2029年9月 |
| Java 21 | LTS | 2023年9月 | 2028年9月 | 2031年9月 |
| Java 23 | 非LTS | 2024年9月 | 2025年3月 | Not Available |
| Java 25 | LTS | 2025年9月 | 2030年9月 | 2033年9月 |
| Java 26 | 非LTS | 2026年3月 | 2026年9月 | Not Available |
Java 23のPremier Supportは2025年3月に終了しています。Extended Supportが存在しない以上、有償で延命する道もありません。本番環境にJava 23が残っているなら、最終ビルドの2025年1月21日を起点に1年半以上、セキュリティ更新を受け取らないまま動き続けている計算になります。バイナリ自体はAdoptiumのアーカイブから今も取得できますが、更新は打ち切られたままです。ディストリビューションごとのサポート条件やライセンスの違いはOpenJDKは商用利用できる?無料の範囲とOracle JDKとの違い・ライセンス・サポート期限【2026年最新】にまとめています。
JavaFX 23とJava Mission Controlの扱い
Java 23の解説記事でJavaFXとJava Mission Controlが「Java 23の新機能」として紹介されていることがありますが、どちらもJDKには同梱されていません。JavaFXはJDK 11以降OpenJFXとして分離された独立プロジェクトで、JavaFX 23はJDK 23とバージョン番号を揃えているだけの別リリースです。導入もJDKとは別で、Maven CentralやGluonが配布するSDKを個別に追加します。Java Mission Control(JMC)も独立したリリースサイクルを持ち、JDKのバージョンとは連動しません。「javafx 23」で本記事にたどり着いたなら、目的の情報はOpenJFXのリリースノート側にあります。JDK 23のJEP一覧に、この2つに関する項目は1件も含まれていません。
プレビューでない3つのJEP
12個のJEPのうち、プレビューでもインキュベーターでもなく確定したのは3つです。プレビュー機能は--enable-previewを外せば無効になりますが、このうちJEP 474とJEP 471はフラグに関係なく挙動と警告が変わるため、移行時に影響が出るのはむしろこちらになります。
Markdownドキュメンテーションコメント(JEP 467)
JavadocコメントをHTMLとJavaDocタグの混在ではなくMarkdownで書けるようになりました。記法は/**ではなく///で始める行コメント形式です。@paramや@seeといった既存のJavaDocタグはそのまま併用できます。
/// 金額を扱うユーティリティ。
///
/// - 単位は**円**(整数)
/// - 端数は切り捨て
///
/// @see java.math.BigDecimal
public final class Money {
/// 税込み金額を返します。
///
/// @param price 税抜き価格
/// @param rate 税率(パーセント)
/// @return 税込み金額
public static int withTax(int price, int rate) {
return price + price * rate / 100;
}
}
JDK 23.0.2のjavadocでこれを処理すると、Markdownの強調とリストがHTMLへ展開されます。生成されたMoney.htmlのクラス説明部分は次のようになりました。
<div class="block"><p>金額を扱うユーティリティ。</p>
<ul>
<li>単位は<strong>円</strong>(整数)</li>
<li>端数は切り捨て</li>
</ul>
</div>
バッククォート3つで囲んだフェンス付きコードブロックも<pre><code>に変換されます。注意点は、既存のHTML混じりコメントを一括変換する機能が用意されていないことです。JEP 467は自動変換を非目標に挙げており、新しく書くクラスから段階的に切り替える運用になります。既存コメントの解釈は変わらないため、混在させても既存のJavadoc出力は壊れません。
ZGCの世代別モード既定化(JEP 474)
-XX:+UseZGCを指定したときの既定が世代別ZGCに切り替わり、同時にZGenerationalオプション自体が非推奨になりました。Java 23では非世代別モードをまだ選べますが、選ぶと警告が2行出ます。JDK 23.0.2での実測は次のとおりです。
$ java -XX:+UseZGC -XX:-ZGenerational -version
OpenJDK 64-Bit Server VM warning: Option ZGenerational was deprecated in version 23.0 and will likely be removed in a future release.
OpenJDK 64-Bit Server VM warning: Non-generational ZGC is deprecated.
openjdk version "23.0.2" 2025-01-21
ZGCそのものの仕組みとG1GCとの使い分けはZGCとは?Javaの低遅延ガベージコレクションの仕組みとG1GCとの違いで解説しています。世代別モードは若い世代と古い世代を分けて回収するため、非世代別モードに合わせてチューニングしたヒープ設定やGCログの前提は崩れます。切り替えによってログ出力とサービサビリティAPIから得られるデータが変わりうる点は、JEP 474自身が明記しているとおりです。
sun.misc.Unsafeのメモリアクセスメソッド非推奨化(JEP 471)
sun.misc.Unsafeの87メソッドのうち、オフヒープおよびオンヒープのメモリにアクセスする79個が削除予定として非推奨になりました。クラス全体の削除は非目標とされており、Java 23の段階ではコンパイル時警告にとどまります。
$ javac -Xlint:deprecation UnsafeUse.java
UnsafeUse.java:9: 警告: [removal] UnsafeのallocateMemory(long)は推奨されておらず、削除用にマークされています
long addr = u.allocateMemory(8);
^
UnsafeUse.java:10: 警告: [removal] UnsafeのputLong(long,long)は推奨されておらず、削除用にマークされています
u.putLong(addr, 42L);
^
UnsafeUse.java:11: 警告: [removal] UnsafeのgetLong(long)は推奨されておらず、削除用にマークされています
System.out.println("read back = " + u.getLong(addr));
^
Java 24ではJEP 498により、同じメソッドを呼ぶと実行時にも警告が出るようになりました。2026年8月時点のJava 26でも削除は実施されておらず、削除時期は決まっていません。代替APIのほうは先に揃っています。JEP 471が移行先として挙げるのはVarHandle API(JEP 193、JDK 9)とFFM API(JEP 454、JDK 22)で、JVMのヒープ外を触る用途はFFM API、ヒープ内はVarHandleが受け持つ形です。キャッシュやシリアライザなどUnsafeを直接使うライブラリを抱えているなら、この79メソッドが依存の中心にあるかどうかを先に確認しておくと移行計画を立てやすくなります。
Java 23で追加された標準APIの実際
JEPを伴う大型のAPI追加はJava 23にはありません。ただし小規模な恒久APIはいくつか入っており、これらはプレビューではないのでフラグなしで使えます。JDK 23.0.2で実行して確認した例を挙げます。
Instant.parse("2024-09-17T00:00:00Z").until(Instant.parse("2025-03-18T00:00:00Z"))
// => PT4368H (Instant.until(Instant) は @since 23)
NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);
nf.isStrict(); // => false(既定は従来どおり寛容な解析)
nf.setStrict(true); // @since 23。厳密解析モードへ切り替え
Inet4Address.ofPosixLiteral("127.1")
// => /127.0.0.1 (@since 23。POSIX形式の短縮表記を解釈)
ほかにSymbolLookup.findOrThrowやMemorySegment.maxByteAlignmentも@since 23で追加されています。「java api 23」で探している対象がこの層であれば、JEP一覧ではなくJava 22から23へのAPI差分を見るほうが早く見つかります。
Java 23のプレビュー機能のその後
試験段階だった9機能のJava 24・25・26での着地
Java 23の12JEPのうち9つは試験段階でした。Java 23を調べる読者が本当に知りたいのは、それらが結局どうなったかです。Java 24・25・26のJEP一覧と突き合わせた対応表を示します。
| Java 23での状態 | 機能 | Java 24 | Java 25 | Java 26 | 2026年8月時点 |
|---|---|---|---|---|---|
| JEP 466 第2プレビュー | Class-File API | JEP 484 正式化 | — | — | 正式 |
| JEP 473 第2プレビュー | Stream Gatherers | JEP 485 正式化 | — | — | 正式 |
| JEP 476 プレビュー | モジュールインポート宣言 | JEP 494 第2プレビュー | JEP 511 正式化 | — | 正式 |
| JEP 481 第3プレビュー | スコープ値 | JEP 487 第4プレビュー | JEP 506 正式化 | — | 正式 |
| JEP 482 第2プレビュー | 柔軟なコンストラクタ本体 | JEP 492 第3プレビュー | JEP 513 正式化 | — | 正式 |
| JEP 477 第3プレビュー | 暗黙宣言クラスとインスタンスmain | JEP 495 第4プレビュー | JEP 512 正式化 | — | 正式(改称) |
| JEP 455 プレビュー | プリミティブ型パターン | JEP 488 第2プレビュー | JEP 507 第3プレビュー | JEP 530 第4プレビュー | プレビュー継続 |
| JEP 480 第3プレビュー | 構造化並行性 | JEP 499 第4プレビュー | JEP 505 第5プレビュー | JEP 525 第6プレビュー | プレビュー継続 |
| JEP 469 第8インキュベーター | Vector API | JEP 489 第9 | JEP 508 第10 | JEP 529 第11 | インキュベーター継続 |
9つのうち6つが正式化され、3つは今も試験段階です。JEP 477はJava 25で正式化される際に名称が「Compact Source Files and Instance Main Methods」へ変わっており、Java 24の時点でも「Simple Source Files and Instance Main Methods」に改称されています。同じ機能を追う場合はJEP番号ではなく名称の変遷に注意してください。Vector APIは11回目のインキュベーターに入っており、Project Valhallaの成果を待つ姿勢が続いています。プレビューのまま据え置かれている3機能は、Java 23で書いたコードが最新版でも--enable-previewを必要とし続けるということです。正式化の見通しを測るなら回数が手がかりになります。JEP 530のプリミティブ型パターンは4回目、JEP 525の構造化並行性は6回目で、いずれも仕様が固まる兆候はまだありません。Java 24での正式化の詳細はJava 24の新機能と主要JEPまとめ|非LTS版の位置づけとJava 25 LTSへの移行判断で個別に扱っています。
Java 23で取り下げられたString Templates
その後を追ううえで見落とせないのが、消えた機能です。Java 21でJEP 430、Java 22でJEP 459としてプレビュー提供されていたString Templates(STR."...")は、JDK 23に含まれませんでした。設計を見直すため取り下げられ、2026年8月時点のJava 26に至るまで復活していません。JDK 23.0.2でコンパイルすると、プレビューフラグを付けていても構文自体が解釈されません。
$ javac --release 23 --enable-preview ST.java
ST.java:4: エラー: エスケープ文字が不正です
String s = STR."Hello \{name}";
^
エラー1個
Java 22でString Templatesを試していたコードは、Java 23へ上げた時点でコンパイルが通らなくなります。プレビュー機能に互換性の保証がないことが実害として現れた例で、バージョンアップの影響調査では非推奨APIと並んで「前の版のプレビュー機能を使っていないか」を確認する必要があります。
主要プレビュー機能のコードと実行結果
ここからは、Java 23で先行して書けた主なプレビュー機能を、JDK 23.0.2で実際にコンパイル・実行した結果とともに見ます。プレビュー機能はコンパイルと実行の両方でフラグが必要です。
$ javac --release 23 --enable-preview Gath.java
$ java --enable-preview Gath
Stream Gatherers(JEP 473)
Stream APIに独自の中間操作を差し込めるようにするAPIです。Stream::gatherと組み込みのGatherersファクトリで、既存の中間操作では書きにくかった処理を表現できます。
List<List<Integer>> win = Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowFixed(2))
.toList();
System.out.println(win);
// => [[1, 2], [3, 4], [5]]
List<List<Integer>> sliding = Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowSliding(3))
.toList();
System.out.println(sliding);
// => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
要素数がウィンドウ幅で割り切れないとき、windowFixedは末尾に端数のウィンドウ[5]をそのまま残します。切り捨てられないため、固定長前提で後続処理を書くと最後のウィンドウで想定外のサイズを受け取る点に注意が必要です。この機能はJava 24でJEP 485として正式化済みで、Java 24以降はフラグなしで同じコードが動きます。
モジュールインポート宣言(JEP 476)
import module java.base;と1行書くだけで、そのモジュールがエクスポートする全パッケージを一括インポートできます。インポートする側がモジュール化されている必要はありません。
import module java.base;
public class ModImp {
public static void main(String[] args) {
Map<String, Integer> m = Stream.of("apple", "kiwi")
.collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(m);
// => {apple=5, kiwi=4}
}
}
java.util.Map、java.util.stream.Stream、java.util.stream.Collectors、java.util.function.Functionを個別にインポートせずコンパイルが通ります。Java 25でJEP 511として正式化済みです。ただし複数モジュールを一括インポートすると同名型の衝突が起きうるため、業務コードでの多用より学習用・スクリプト用途に向いた機能です。
柔軟なコンストラクタ本体(JEP 482)
super(...)やthis(...)の呼び出し前に文を書けるようになりました。従来は引数の検証を三項演算子やstaticメソッドに押し込む必要がありましたが、そのまま書けます。
public class Flex extends Base {
Flex(int v) {
if (v < 0) throw new IllegalArgumentException("v must be >= 0, got " + v);
super(v * 2);
System.out.println("Flex ctor done");
}
}
// new Flex(5) => Base ctor v=10 のあと Flex ctor done
// new Flex(-1) => IllegalArgumentException: v must be >= 0, got -1
new Flex(-1)では例外が先に飛ぶため、親クラスのコンストラクタは実行されません。不正な状態のオブジェクトが一瞬でも生成されるのを防げます。Java 25でJEP 513として正式化されました。
プリミティブ型パターン(JEP 455)
instanceofとswitchのパターンにプリミティブ型を書けるようにする提案です。値が対象の型に収まるかどうかで分岐します。
static String widen(int i) {
return switch (i) {
case byte b -> "fits in byte: " + b;
case short s -> "fits in short: " + s;
case int x -> "needs int: " + x;
};
}
// widen(42) => fits in byte: 42
// widen(40000) => needs int: 40000
// widen(1_000_000) => needs int: 1000000
40000はshortの上限32767を超えるためcase shortには入りません。この機能はJava 26のJEP 530でも第4プレビューのままです。仕様が固まっていない段階なので、業務コードで使うのは避けたほうが無難です。
Class-File API(JEP 466)
クラスファイルの解析・生成・変換を標準APIで行うためのもので、ASMなど外部ライブラリへの依存を減らせます。
ClassModel cm = ClassFile.of().parse(Path.of("Gath.class"));
System.out.println(cm.majorVersion());
// => 67
cm.methods().forEach(m -> System.out.println(m.methodName().stringValue()));
// => <init> と main
メジャーバージョン67がJava 23のクラスファイル形式を指します。Java 24でJEP 484として正式化され、パッケージjava.lang.classfileがフラグなしで使えるようになりました。
Java 23からのバージョンアップ影響調査
Java 23が残っている環境をアップグレードする場合、調査すべき対象は言語機能ではなく削除・非推奨の側です。標準APIと内部APIでは検出に使うツールが分かれます。
jdeprscanとjdepsの守備範囲
削除予定として非推奨になった標準APIはjdeprscanで検出できます。
$ jdeprscan --release 23 --for-removal Depr.class
class Deprが非推奨メソッドjava/lang/Integer::<init>(I)Vを使用しています (forRemoval=true)
class Deprが非推奨メソッドjava/lang/System::getSecurityManager()Ljava/lang/SecurityManager;を使用しています (forRemoval=true)
ところが、同じコマンドをJEP 471で非推奨になったsun.misc.Unsafeのメモリアクセスメソッドを呼ぶクラスに対して実行すると、出力は空でした。sun.misc.UnsafeはJDK内部APIであり、jdeprscanの走査対象である標準APIに含まれないためです。内部APIへの依存はjdepsで調べます。
$ jdeps --jdk-internals UnsafeUse.class
UnsafeUse.class -> jdk.unsupported
UnsafeUse -> sun.misc.Unsafe JDK internal API (jdk.unsupported)
影響調査でjdeprscanだけを回して「該当なし」と結論づけると、Unsafe依存を丸ごと見落とします。標準APIはjdeprscan --for-removal、内部APIはjdeps --jdk-internals、この2本を必ずセットで走らせてください。Java 8や11からのシステム近代化案件でも同じ2本が起点になります。ただし近代化の移行先としてJava 23を経由する意味はありません。サポートが切れているうえ、Java 23固有の恒久機能もMarkdownドキュメンテーションコメントだけだからです。Java 8・11から上げるなら25 LTSへ直接向かうのが最短になります。
ZGenerationalを明示指定している場合の扱い
Java 23の起動オプションに-XX:-ZGenerationalを書いて非世代別ZGCを使い続けている環境は、移行先のバージョンによって結果が3段階に分かれます。JEP 490がJava 24で非世代別モードのコードごと削除し、その後オプション自体が失効したためです。Temurinの各版で実際に起動して確認しました。
| 実行したJDK | 起動 | 使われるZGC | 出力メッセージ |
|---|---|---|---|
| 23.0.2 | 成功 | 非世代別 | 非推奨警告2行 |
| 25.0.4 | 成功 | 世代別 | Ignoring option ZGenerational; support was removed in 24.0 |
| 26.0.2 | 失敗 | — | Unrecognized VM option ‘ZGenerational’ |
$ java -XX:+UseZGC -XX:-ZGenerational -version (JDK 26.0.2)
Unrecognized VM option 'ZGenerational'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Java 25までは起動するため、警告を見落とすとGCの動作が静かに世代別へ切り替わったことに気づけません。一方Java 26では、JEP 490が予告していた「オプションが失効しHotSpot JVMが認識せず起動を拒否する」段階に実際に到達しており、オプションを残したままアップグレードするとアプリケーションが起動しません。移行前にオプション自体を削除し、世代別ZGC前提でヒープとGCログの監視設定を組み直してください。
Java 23からの移行先の選び方
2026年8月時点でJava 23を新規採用する理由はありません。サポートが切れており、Java 23限定の機能も存在しないためです。移行先は次の3択で考えます。
本命のJava 25 LTS
Premier Supportが2030年9月まで、Extended Supportが2033年9月まであります。Java 23で試験段階だった9機能のうち6つは、Java 25までにすべて正式化されました。Java 23で--enable-preview付きで書いたモジュールインポート宣言・スコープ値・柔軟なコンストラクタ本体・暗黙宣言クラスは、Java 25ではフラグを外すだけで動きます。ディストリビューションの選定とライセンス条件はOpenJDKは商用利用できる?無料の範囲とOracle JDKとの違い・ライセンス・サポート期限【2026年最新】を参照してください。
Java 26を選ぶ条件
HTTP/3対応のHTTPクライアント(JEP 517)など26固有の機能が要る場合に限られます。非LTSなのでPremier Supportは2026年9月まで、本記事の公開時点で残り1か月ほどしかありません。半年ごとに追随し続ける体制がないなら選ぶべきではありません。26で何が変わるかは2026年3月リリースのJava 26で開発者が押さえるべき10個のJEPと全体像にまとめています。前述のとおり-XX:-ZGenerationalが残っていると起動しない点にも注意してください。
Java 21 LTSへ下げる判断
既存資産の大半が21で動いており、Java 23固有のプレビュー機能を使っていないなら現実的な選択です。Premier Supportは2028年9月まで残っています。Java 17 LTSまで下げるのは勧めません。17のPremier Supportは2026年9月で終わり、以降はExtended Support(2029年9月まで)の領域に入るため、23から下げる先としては21より運用条件が悪くなります。
よくある質問
Java 23は今も使えますか?
動作はしますが、セキュリティ更新は受け取れません。OracleのPremier Supportは2025年3月に終了し、Extended Supportは提供されていません。Eclipse Temurinの最終ビルドも2025年1月21日の23.0.2です。本番環境で使い続けるのは推奨できません。
Java 23からアップグレードするならどのバージョンですか?
Java 25 LTSが基本です。Premier Supportが2030年9月まであり、Java 23でプレビューだったモジュールインポート宣言・スコープ値・柔軟なコンストラクタ本体・暗黙宣言クラスが正式化されているため、コードの手直しが最小で済みます。
JavaFX 23はJava 23に含まれますか?
含まれません。JavaFXはJDK 11以降OpenJFXとして分離された別プロジェクトで、バージョン番号がJDKと揃っているだけです。JDK 23の12個のJEPにJavaFX関連の項目はなく、Java Mission Controlも別のリリースサイクルで動いています。詳しくは本文の「JavaFX 23とJava Mission Controlの扱い」をご覧ください。
Java 23で追加されたAPIは何ですか?
JEPを伴う大型のAPI追加はありませんが、小規模な恒久APIはいくつか入っています。Instant.until(Instant)、NumberFormat.isStrict()とsetStrict(boolean)、Inet4Address.ofPosixLiteral(String)、SymbolLookup.findOrThrow(String)などが@since 23で追加されました。一方、Class-File API(java.lang.classfile)とStream Gatherers(Stream::gather)はJava 23ではプレビューAPIで--enable-previewが必要でした。この2つはJava 24で正式化されています。
Markdownドキュメンテーションコメントはどう書きますか?
/**ではなく///で始まる行コメントを連ねる形式です。本文にMarkdownの見出し・リスト・強調・フェンス付きコードブロックが書け、@paramや@returnなどのJavaDocタグも併用できます。既存のHTML混じりコメントを自動変換する機能はないため、新規クラスから段階的に切り替える運用になります。