Javaをとりまく現状と、Java 26への期待

2026年3月18日、Java 26が正式にリリースされました。
「Javaってまだ現役なの?」という声を聞くことも正直あるんですが、実態はまったく逆です。TIOBE Indexでは常にトップ5をキープしていますし、エンタープライズ領域ではJavaなしに語れないシステムが山ほどあります。Spring Boot、Quarkus、Micronaut といったフレームワークのエコシステムも年々充実しており、クラウドネイティブな環境との相性もどんどん良くなっています。
そんなJavaの最新バージョンが Java 26 です。今回のリリースの目玉は大きく4つ。HotSpot VMの起動高速化、G1 GCのスループット向上、HTTP/3クライアント対応、そしてアプレットAPIの完全削除です。
特に起動高速化とGCの改善は、コンテナ環境でJavaアプリを動かしているチームにとって、ぶっちゃけかなり嬉しいアップデートなんですよね。コールドスタートの遅さに悩まされてきた人は少なくないはずです。
この記事では、Java 26の新機能を一つずつ掘り下げて解説します。実際にSDKMANでインストールして試してみたセクションも用意したので、手を動かしたい方もぜひ参考にしてください。
Javaのリリース戦略(LTSと非LTSの違い)
Java 26の話に入る前に、Javaのリリースサイクルについて整理しておきます。ここを理解しておかないと「どのバージョンを使えばいいのか」が分からなくなるので。
Java 9以降、Javaは6カ月ごとのフィーチャーリリースを採用しています。毎年3月と9月に新しいバージョンが出るスケジュールです。そして、その中から一部のバージョンがLTS(Long-Term Support)として長期サポートの対象になります。
バージョン | リリース時期 | サポート種別 | 備考 |
|---|---|---|---|
Java 21 | 2023年9月 | LTS | 現在多くの本番環境で採用 |
Java 22 | 2024年3月 | 非LTS | — |
Java 23 | 2024年9月 | 非LTS | — |
Java 24 | 2025年3月 | 非LTS | AOTキャッシュ初登場(JEP 483) |
Java 25 | 2025年9月 | LTS | 最新の長期サポート版 |
Java 26 | 2026年3月 | 非LTS | 今回のリリース |
LTSは2年ごと(Java 17→21→25)にリリースされる傾向があり、Oracle や各ベンダーから最低8年間のアップデートが提供されます。一方、非LTSのバージョンは次のリリースが出るまでの6カ月間しかサポートされません。
つまり、本番環境には LTS を使い、非LTSは新機能の検証やプレビュー目的で活用するのがセオリーです。Java 26は非LTSなので、今すぐプロダクション環境を切り替える必要はありません。ただ、Java 26で正式化された機能は次のLTSであるJava 29(予想)にも引き継がれるため、「次のLTSに何が入るか」を把握しておく意味でも、今回のリリース内容を追いかけておく価値は十分あります。
Java 26 主な新機能
ここからが本題です。Java 26に含まれる主要なJEP(JDK Enhancement Proposal)を、それぞれ詳しく見ていきます。
JEP 516: AOTオブジェクトキャッシング
まず最も注目度が高いのが、JEP 516: Ahead-of-Time Object Caching with Any GC です。
Java 24で導入されたJEP 483のAOT(Ahead-of-Time)キャッシュは、アプリケーションのクラスやオブジェクトを事前にキャッシュしておくことで、JVMの起動時間とウォームアップ時間を短縮する仕組みです。Spring PetClinicのデモでは、約21,000クラスのキャッシュにより起動時間が41%短縮されたという報告があります。
ただし、Java 24〜25のAOTキャッシュには制約がありました。キャッシュされたオブジェクトがGC(ガベージコレクタ)固有のメモリレイアウトに依存していたため、ZGC(Z Garbage Collector)では使えなかったのです。ZGCはオブジェクト参照にメタデータビットを埋め込む独自フォーマットを採用しているため、SerialやG1で作ったキャッシュをそのまま読み込めなかったんですよね。
JEP 516は、この問題をGC非依存の中間フォーマットを導入することで解決しました。具体的には、キャッシュ内のオブジェクト参照を64ビットメモリアドレスではなく「論理インデックス」として保存します。
従来のキャッシュでは、Stringオブジェクトのvalueフィールドにbyte配列のメモリアドレスがそのまま書かれていました。
// 従来(GC固有フォーマット)
header: ... | value: 0x4002045278 | coder: ... | hash: ... | hashIsZero: ...JEP 516では、これが論理インデックスに置き換わります。
// JEP 516(GC非依存フォーマット)
header: ... | value: 5 | coder: ... | hash: ... | hashIsZero: ...JVM起動時にバックグラウンドスレッドがキャッシュからオブジェクトを順次読み出し、使用中のGCに合った形式でメモリ上に再構成(マテリアライズ)します。メモリマッピングではなくストリーミング方式を採用することで、どのGCでも動くようになったわけです。
これにより、ZGCでレイテンシを最小化しつつ、AOTキャッシュで起動時間も短縮するという「二兎を追う」運用がついに可能になりました。コンテナ環境でスケールアウトする際のコールドスタート問題と、GCによるテールレイテンシ問題を同時に対処できるのは、実運用においてかなり大きいです。
さらに副次的なメリットとして、JDKにGC非依存のベースラインAOTキャッシュを同梱できるようになるため、特別な設定なしでもある程度の起動高速化が得られる将来が見えてきます。
JEP 522: G1 GCのスループット向上
続いて、JEP 522: G1 GC: Improve Throughput by Reducing Synchronization です。
G1 GCはJava 9以降のデフォルトGCで、レイテンシとスループットのバランスを重視した設計になっています。ただ、ParallelやSerial GCといったスループット特化型のGCと比べると、アプリケーションスレッドとGCスレッドの間で同期処理が多く走るため、スループットがやや犠牲になっていました。
G1 GCの仕組みを簡単に説明すると、ヒープメモリをリージョンに分割し、生存オブジェクトを新しいリージョンにコピーすることでメモリを回収します。このとき、どのリージョン間にオブジェクト参照があるかを「カードテーブル」というデータ構造で追跡しています。オブジェクト参照が書き換わるたびに、アプリケーションに注入された「ライトバリア」コードがカードテーブルを更新する仕組みです。
問題は、このカードテーブルの最適化をバックグラウンドで行うスレッドと、アプリケーションスレッドの間で同期が必要だったこと。ライトバリアのコードは複雑で遅く、x64アーキテクチャでは約50命令も必要でした。
JEP 522の解決策はシンプルかつ効果的です。カードテーブルを2つ用意するのです。
項目 | 従来のG1 GC | JEP 522適用後 |
|---|---|---|
カードテーブル数 | 1つ | 2つ(交互に使用) |
ライトバリア命令数(x64) | 約50命令 | 約12命令 |
アプリ-GC間の同期 | 頻繁に必要 | ほぼ不要 |
追加メモリ | — | ヒープ1GBあたり約2MB |
アプリケーションスレッドが第1テーブルを更新している間、オプティマイザスレッドは第2テーブルに対して作業します。スキャン対象が多くなりすぎそうなタイミングで、2つのテーブルをアトミックにスワップ。これによりアプリケーションスレッドは空のテーブルに切り替わり、同期を待つ必要がなくなります。
効果は実測でスループット5〜15%向上。オブジェクト参照の更新が多いアプリケーションでは特に効果が大きく、ライトバリアの簡素化によって参照更新が少ないアプリでも最大5%の改善が確認されています。GCポーズ時間もわずかに短縮されるというおまけ付きです。
追加のネイティブメモリ使用量はヒープ1GBあたり約2MBと、ほぼ無視できるレベルです。従来使っていた補助データ構造を置き換える形になるため、場合によってはむしろメモリ消費が減ることもあるとのこと。
JEP 517: HTTP/3クライアントサポート

JEP 517: HTTP/3 for the HTTP Client API は、Java 11で導入されたjava.net.http.HttpClient APIにHTTP/3サポートを追加するものです。
HTTP/3は2022年にIETFで標準化されたプロトコルで、TCP + TLSの代わりにQUICというUDPベースのトランスポートプロトコルを使います。すでに主要ブラウザはHTTP/3に対応しており、全Webサイトの約3分の1がHTTP/3をデプロイしているという状況です。Javaのクライアント側もそろそろ対応して当然、という流れですね。
HTTP/3の主なメリットをまとめると以下のとおりです。
特徴 | HTTP/2(TCP) | HTTP/3(QUIC) |
|---|---|---|
トランスポート | TCP + TLS 1.2/1.3 | QUIC(UDP + TLS 1.3組み込み) |
ハンドシェイク | TCP 3-way + TLS = 2〜3 RTT | 0〜1 RTT(0-RTT再接続可能) |
Head-of-Line Blocking | TCPレベルで発生 | ストリーム単位で独立、影響なし |
パケットロス耐性 | 全ストリームに影響 | 該当ストリームのみ影響 |
接続マイグレーション | 非対応 | 対応(Wi-Fi → モバイル等) |
Java 26でHTTP/3を使うには、明示的なオプトインが必要です。デフォルトのプロトコルバージョンはHTTP/2のまま変更されていません。
// HttpClient全体でHTTP/3を優先
var client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_3)
.build();
// または個別リクエストでHTTP/3を指定
var request = HttpRequest.newBuilder(URI.create("https://example.com/"))
.version(HttpClient.Version.HTTP_3)
.GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());サーバーがHTTP/3に対応していない場合は、自動的にHTTP/2やHTTP/1.1にフォールバックしてくれます。既存のコードに.version(HttpClient.Version.HTTP_3)を1行足すだけで試せるのが良いですね。
プロトコルバージョンのネゴシエーション方法は4パターン用意されています。
方式 | 動作 | ユースケース |
|---|---|---|
HttpRequestでHTTP_3指定 | HTTP/3を試行→タイムアウトでフォールバック | HTTP/3対応サーバーが多い環境 |
HttpClientでHTTP_3指定 | HTTP/3とHTTP/2を並行試行→先に成功した方を使用 | 対応状況が不明な環境 |
ALT_SVCモード | まずHTTP/2で接続→Alt-Svcヘッダでhttp/3発見後に切替 | 安全に段階的移行したい場合 |
HTTP_3_URI_ONLYモード | HTTP/3のみ。失敗時はフォールバックしない | サーバーがHTTP/3対応と分かっている場合 |
なお、QUIC自体のAPIは提供されず、サーバーサイドのHTTP/3実装もスコープ外です。あくまでクライアントとしてHTTP/3を喋れるようになったという位置づけです。
JEP 504: アプレットAPI削除
JEP 504: Remove the Applet API は、ついにアプレットAPIが完全に削除されたというお知らせです。
Javaアプレット、覚えていますか? ブラウザ上でJavaプログラムを動かすための技術で、1990年代後半〜2000年代前半には一世を風靡しました。しかし、セキュリティ上の問題やFlash・JavaScriptの台頭により、Java 9(2017年)で非推奨化、Java 17(2021年)で「削除予定(forRemoval)」とマークされていました。
Java 26で、java.appletパッケージと関連クラスがようやくJDKから完全に除去されます。今さらアプレットAPIを使っているプロジェクトはほぼないとは思いますが、古い依存ライブラリが内部でアプレット関連のクラスを参照しているケースは稀にあるので、アップグレード時には一応チェックしておくといいです。
実際にJava 26を試してみた

百聞は一見にしかず。実際にJava 26をインストールして、AOTキャッシュとHTTP/3を試してみます。
セットアップ
SDKMANを使えば簡単にインストールできます。
# SDKMANでJava 26をインストール
sdk install java 26-open
# バージョン確認
java -version
# openjdk version "26" 2026-03-18
# OpenJDK Runtime Environment (build 26+36-2369)
# OpenJDK 64-Bit Server VM (build 26+36-2369, mixed mode, sharing)AOTキャッシュを試す
AOTキャッシュの効果を体感するために、簡単なSpring Bootアプリの起動時間を比較してみます。
# Step 1: トレーニングラン(キャッシュを作成)
java -XX:AOTCacheOutput=app.aot -jar myapp.jar
# Step 2: キャッシュを使って起動
java -XX:AOTCache=app.aot -jar myapp.jarトレーニングランでは、アプリケーションが使用するクラスやオブジェクトがキャッシュファイル(app.aot)に保存されます。2回目以降の起動では、このキャッシュを読み込むことで、クラスローディングとリンキングをスキップできます。
体感としては、Spring Bootアプリの起動が2.5秒 → 1.5秒程度に短縮されました。アプリの規模やクラス数によって効果は変わりますが、「あ、本当に速くなってる」と実感できるレベルです。
Java 26からはZGCとの組み合わせも可能なので、以下のようにZGCを指定しつつAOTキャッシュを使えます。
# ZGC + AOTキャッシュの組み合わせ(Java 26から可能に!)
java -XX:+UseZGC -XX:AOTCache=app.aot -jar myapp.jarJava 25まではこの組み合わせがエラーになっていたので、地味に嬉しいアップデートです。
HTTP/3クライアントを試す
次にHTTP/3クライアントを試してみます。
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Http3Demo {
public static void main(String[] args) throws Exception {
// HTTP/3を優先するクライアントを作成
var client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_3)
.build();
var request = HttpRequest.newBuilder(
URI.create("https://www.google.com/"))
.GET()
.build();
var response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Protocol: " + response.version());
System.out.println("Body length: " + response.body().length());
}
}# コンパイル&実行
javac Http3Demo.java
java Http3Demo
# Status: 200
# Protocol: HTTP_3
# Body length: 18247レスポンスのversion()で実際にHTTP/3が使われたことを確認できます。サーバーがHTTP/3非対応の場合は自動的にHTTP/2にフォールバックするので、既存コードを壊す心配はありません。
実際に動かしてみた感想としては、API自体の使い勝手は従来とほぼ同じで、プロトコルバージョンを1行指定するだけ。「え、これだけ?」という手軽さです。内部ではQUICのハンドシェイクやUDPソケットの管理が行われているわけですが、開発者がそれを意識する必要はまったくありません。
Project Detroit — JavaとJavaScript・Python共存の未来
Java 26のJEPからは少し外れますが、JavaOne 2026で発表されたProject Detroitについても触れておきます。
Project Detroitは、Javaの中にV8(JavaScriptエンジン)とCPython(Pythonインタプリタ)を組み込むプロジェクトです。つまり、JVM上でJavaScript・Pythonのコードをネイティブに実行できるようにしようという試みです。
「あれ、それってGraalVMの多言語実行と同じじゃない?」と思った方、鋭いです。GraalVMはTruffleフレームワークを介して多言語をサポートしていますが、Project DetroitはV8とCPythonそのものをJVMに統合するアプローチです。これにより、各言語の本家ランタイムとの互換性を最大限に確保しつつ、Java ↔ JavaScript/Python間のシームレスなデータ共有を実現しようとしています。
まだ正式なJEPにはなっていませんが、実現すればJavaのエコシステムが一気に広がります。MLモデルの推論にPythonライブラリをそのまま使ったり、Node.jsのnpmパッケージをJavaアプリに組み込んだり。マイクロサービスアーキテクチャにおける「言語の壁」がかなり低くなりそうです。
ただし、セキュリティモデルやメモリ管理の統合など、解決すべき課題は山積みです。実用段階に達するのはもう少し先になるとは思いますが、方向性としてはかなりワクワクするプロジェクトです。
アップグレード時の注意点
Java 26へのアップグレードを検討する場合、いくつかの注意点があります。
チェック項目 | 詳細 | 影響度 |
|---|---|---|
アプレットAPI依存の確認 |
| 中 |
非LTSであることの認識 | サポート期間は6カ月(2026年9月まで)。本番環境ではJava 25 LTSを推奨 | 高 |
AOTキャッシュの再生成 | JDKバージョンが変わるとキャッシュファイルの互換性がない場合あり。再トレーニングが必要 | 低〜中 |
G1 GCメモリ使用量 | カードテーブル2枚分のネイティブメモリ追加(ヒープ1GBあたり約2MB)。実質的には無視できるレベル | 低 |
HTTP/3はオプトイン | デフォルトではHTTP/2のまま。明示的に | 低 |
ビルドツールの対応 | Maven/GradleのJava 26対応バージョンを確認すること | 中 |
特に注意すべきは、Java 26は非LTSであるという点です。開発・検証環境で新機能を試すのは大いに推奨しますが、プロダクション環境は引き続きJava 25(LTS)をベースにするのが安全です。
アプレットAPI削除の影響を確認するには、jdeprscanツールが便利です。
# 依存ライブラリのJAR内で非推奨・削除APIの使用をスキャン
jdeprscan --release 26 your-library.jarこれでjava.applet関連の参照があれば警告が出ます。早めにチェックしておくと、次のLTSへの移行がスムーズになります。
まとめ
Java 26は非LTSリリースながら、実用性の高い改善が詰まったバージョンです。
JEP 516(AOTオブジェクトキャッシング)により、ZGCを含むすべてのGCでAOTキャッシュが利用可能になりました。低レイテンシと高速起動の両立という、長らく「どちらかを選ぶしかない」と思われていた制約が取り払われたのは大きな前進です。
JEP 522(G1 GCスループット向上)は、カードテーブルの二重化というエレガントなアプローチで5〜15%のスループット改善を実現。デフォルトGCのパフォーマンスが底上げされるため、何もしなくても恩恵を受けられます。
JEP 517(HTTP/3クライアント)は、Javaアプリケーションを現代のWebプロトコルに対応させる重要な一歩です。1行の変更で試せる手軽さも好印象です。
そしてJEP 504(アプレットAPI削除)は、Javaが過去の遺産を整理し、よりスリムなプラットフォームを目指していることの表れです。
Java 26を今すぐ本番投入する必要はありませんが、開発環境で試しておくことで次のLTSへの準備ができます。特にコンテナ環境でJavaを運用しているチームは、AOTキャッシュ + ZGCの組み合わせをぜひ検証してみてください。起動時間とGCレイテンシの両方が改善される体験は、なかなか感動的ですよ。















