【徹底解説】Java 24 新機能まとめ(2024年9月リリース)
はじめに
2024年9月17日(米国時間)、Javaの新たなマイルストーンとなる「Java 24」(JDK 24)が正式にリリースされる予定です。Oracleが主導する6ヶ月ごとの迅速なリリースサイクルは、Javaプラットフォームが現代のソフトウェア開発の要求に機敏に対応し、進化し続けることを可能にしています。Java 24は、Java 23に続くフィーチャーリリースであり、長期サポート(LTS)版ではありませんが、開発者の生産性向上、パフォーマンスの最適化、そしてJava言語自体の学習しやすさを追求する、数多くの重要な改善と新機能を含んでいます。
Javaは、大規模エンタープライズシステムからクラウドネイティブなマイクロサービス、Androidアプリ、そしてデータサイエンスの領域まで、その活躍の場を広げ続けています。この進化の背景には、Project Amber(言語機能の改善)、Project Loom(軽量な並行処理)、Project Panama(ネイティブコード連携の改善)、Project Valhalla(メモリレイアウトとパフォーマンスの最適化)といった、長期的な研究開発プロジェクトの存在が不可欠です。Java 24で導入される機能の多くも、これらのプロジェクトから生まれた成果がプレビュー版や最終版として具体化されたものです。
この記事では、Java 24で導入される予定の主要な新機能(JEP: JDK Enhancement Proposal)を、一つひとつ詳細に掘り下げて解説します。各機能が「どのような問題を解決するために生まれたのか(背景と動機)」、「具体的にどのように使うのか(コード例)」、そして「開発者にどのようなメリットをもたらすのか」を、約5000語のボリュームで網羅的にご紹介します。
Java初学者から経験豊富なベテラン開発者まで、すべてのJavaに関わる方々がJava 24の新機能をキャッチアップし、日々のコーディングに活かすための一助となれば幸いです。
【ご注意】
この記事は、2024年9月の正式リリースに先立ち、公開されているJEP(JDK Enhancement Proposal)の草案やターゲット情報に基づいて執筆しています。正式リリースまでに内容が変更される可能性がある点にご留意ください。
Part 1: 言語機能の進化 (Project Amber)
Project Amberは、Java言語をよりモダンで、より簡潔に、そしてより安全に記述できるようにするためのプロジェクトです。Java 24では、特にJavaの学習体験を劇的に改善する機能や、レコードクラスの利便性を高める機能がプレビュー版として導入されます。
JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)
これは、Java 24における最も注目すべき機能の一つであり、Javaの学習方法を根底から変える可能性を秘めています。この機能は、Java初学者が直面する「おまじない」と呼ばれる定型的なコードを削減し、プログラムの本質的なロジックに集中できるようにすることを目的としています。
背景と動機
Javaを学び始めるとき、誰もが最初に書くであろう “Hello, World!” プログラムを思い出してください。
java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
このわずか1行の出力を得るために、public class ...
、public static void main(String[] args)
という、初学者にとっては意味を理解するのが難しい多くのキーワードを記述する必要があります。これらはJavaのプログラム構造を支える重要な概念ですが、最初のステップとしてはあまりにも大きな認知的負荷です。多くの教育現場では、これらを「おまじない」として説明し、後で学ぶように指導しますが、これは学習意欲を削ぐ一因となっていました。
この問題を解決するため、JEP 477はよりシンプルなプログラム記述を可能にします。この提案は、Java 21のJEP 445、Java 22のJEP 463に続く3回目のプレビューであり、フィードバックを元に洗練されています。
詳細な解説
JEP 477は、主に2つの大きな変更を導入します。
-
暗黙的に宣言されるクラス (Implicitly Declared Classes)
明示的なclass
宣言なしに、ソースファイルに直接コードを記述できるようになります。コンパイラは、そのようなコードを含むソースファイルを、名前のないクラス(unnamed class)として扱います。 -
インスタンス
main
メソッド (Instancemain
Methods)
main
メソッドをstatic
にする必要がなくなります。これにより、main
メソッドからクラスのインスタンスフィールドやメソッドに直接アクセスできるようになり、よりオブジェクト指向的な思考でプログラムを始められます。
これらの変更を組み合わせることで、先の “Hello, World!” プログラムは劇的にシンプルになります。
【After: Java 24 (Preview)】
java
void main() {
System.out.println("Hello, World!");
}
あるいは、インスタンスフィールドを使うこともできます。
“`java
String greeting = “Hello, Universe!”;
void main() {
System.out.println(greeting);
}
“`
何が起きているのか?
class MyProgram { ... }
のようなクラス宣言が不要になりました。コンパイラがこのファイルを暗黙的なクラスとして扱います。public static void main(String[] args)
がvoid main()
に簡略化されました。public
やstatic
修飾子、String[] args
パラメータが不要です(ただし、必要であればvoid main(String[] args)
と書くことも可能です)。main
メソッドがインスタンスメソッド(非static
)になったため、greeting
というインスタンスフィールドに直接アクセスできています。
この機能は、あくまでJavaプログラムの「エントリーポイント(入口)」を簡素化するものです。複数のクラスファイルからなる大規模なプログラムでは、従来通りの明示的なクラス宣言が引き続き中心的な役割を果たします。この機能の主眼は、教育、小規模なユーティリティ作成、プロトタイピングの場面で、Javaをより手軽に利用できるようにすることにあります。
ステータスと今後の展望
JEP 477は「Third Preview」です。これは、機能がまだ実験段階であり、開発者コミュニティからのフィードバックを求めていることを意味します。この機能を試すには、コンパイル時と実行時に --enable-preview
フラグと --source 24
フラグを指定する必要があります。
“`bash
コンパイル
javac –release 24 –enable-preview HelloWorld.java
実行
java –enable-preview HelloWorld
“`
3回目のプレビューということで、機能の安定性は高まっていますが、今後のJavaバージョンで最終版(Final)となる際には、さらに細かな調整が加えられる可能性があります。この機能は、JavaがPythonやJavaScriptのようなスクリプト言語の手軽さを取り入れつつ、静的型付けや堅牢性といった本来の強みを維持するための重要な一歩と言えるでしょう。
JEP 468: Derived Record Creation (Preview)
レコード(Records)はJava 16で導入され、DTO(Data Transfer Object)や値オブジェクトのような、不変なデータを保持するクラスを簡潔に定義するための機能として広く受け入れられています。しかし、レコードの不変性ゆえの課題もありました。それは、「一部のプロパティだけが異なる新しいインスタンスを作成する」のが少し面倒であるという点です。
背景と動機
例えば、Point
というレコードがあるとします。
java
record Point(int x, int y) {}
この Point
インスタンス p1
の y
座標だけを変更した新しいインスタンス p2
を作りたい場合、これまでは次のように書く必要がありました。
java
// Before
Point p1 = new Point(10, 20);
Point p2 = new Point(p1.x(), 30); // yだけ変えたいが、xも再度指定する必要がある
フィールドが増えれば増えるほど、この記述は冗長になり、エラーも起こしやすくなります。他の言語では、このような操作をより簡潔に記述するための構文(例えば、Kotlinの copy
メソッドやC#の with
式)が提供されています。JEP 468は、Javaのレコードにも同様の利便性をもたらすことを目的としています。
詳細な解説
JEP 468は、レコードのための with
式を導入します。これにより、既存のレコードインスタンスを元に、指定したフィールドの値を変更した新しいインスタンスを、簡潔かつ安全に生成できます。
【After: Java 24 (Preview)】
“`java
// JEP 468を適用した例
Point p1 = new Point(10, 20);
Point p2 = p1 with { y = 30; }; // ‘with’式でyだけを変更
// p2は Point[x=10, y=30] となる
System.out.println(p2);
“`
この with
式は、見た目がシンプルになるだけでなく、いくつかの重要な利点があります。
- 不変性の維持:
with
式は元のインスタンス (p1
) を変更しません。常に新しいインスタンス (p2
) を生成します。これはレコードの設計思想と完全に一致しています。 - 可読性の向上: どのフィールドが変更されたのかが一目瞭然です。
- 安全性の確保: コンストラクタを直接呼び出すわけではないため、コンストラクタで定義された検証ロジックも適切に実行されます。
with
式は、内部的には正規コンストラクタ(canonical constructor)を呼び出すように変換されるため、一貫性が保たれます。
複数のフィールドを同時に変更することも可能です。
“`java
record Person(String name, int age, String city) {}
Person person1 = new Person(“Alice”, 30, “New York”);
Person person2 = person1 with {
age = 31;
city = “London”;
};
// person2は Person[name=Alice, age=31, city=London]
System.out.println(person2);
“`
ステータス
JEP 468は「Preview」機能として提案されています。これも --enable-preview
フラグを付けて試すことができます。レコードを多用するアプリケーション、特にイミュータブルなデータモデルを扱うドメイン駆動設計(DDD)や関数型プログラミングのスタイルを取り入れているプロジェクトにおいて、非常に強力な武器となるでしょう。
Part 2: APIとライブラリの進化
Javaプラットフォームの強みは、その豊富で安定した標準ライブラリにあります。Java 24では、特に開発者のドキュメンテーション体験を向上させる大きな変更が加えられます。
JEP 467: Markdown Documentation Comments
Java開発者にとって、Javadocはコードの仕様を記述し、APIドキュメントを生成するための不可欠なツールです。しかし、そのコメント記法は長年にわたりHTMLタグベースであり、現代の開発者にとっては少し古風で、記述やレビューがしにくいという側面がありました。
背景と動機
従来のJavadocコメントは、次のようにHTMLタグを使って記述する必要がありました。
java
/**
* このメソッドは2つの整数を加算します。
* <p>
* 使用例:
* <pre>{@code
* int result = add(5, 3); // result は 8
* }</pre>
*
* @param a 最初の整数
* @param b 2番目の整数
* @return 2つの整数の和
* @see Math#addExact(int, int)
*/
public int add(int a, int b) {
return a + b;
}
太字は <b>
、段落は <p>
、コードブロックは <pre>{@code ...}
と、HTMLの知識が必要です。これは、READMEファイルやWikiで広く使われているMarkdown記法に慣れた開発者にとって、直感的ではありませんでした。
JEP 467は、この問題を解決するために、Javadocコメント内でMarkdown記法を直接使用できるようにするものです。
詳細な解説
このJEPにより、Doclet(Javadocツールの一部で、ドキュメントの出力を担当するコンポーネント)がMarkdownを解釈し、適切なHTMLに変換できるようになります。これにより、開発者はより自然で読みやすい形式でドキュメントを記述できます。
【After: Java 24】
java
java
/**
* このメソッドは2つの整数を加算します。
*
* 使用例:
*
* int result = add(5, 3); // result は 8
* *
* @param a 最初の整数
* @param b 2番目の整数
* @return 2つの整数の和
* @see Math#addExact(int, int)
*/
public int add(int a, int b) {
return a + b;
}
変更点を見てみましょう。
- 段落の区切りは、HTMLの
<p>
タグではなく、単純な空行で表現できるようになりました。 - コードブロックは、Markdownの fenced code block(バッククォート3つで囲む形式)で記述できます。言語ヒント(
java
)もサポートされます。 - 太字 (
**bold**
)、イタリック (*italic*
)、箇条書きリストなども、標準的なMarkdown構文で記述できます。
この機能は、CommonMark仕様(広く受け入れられているMarkdownの標準仕様)のサブセットをサポートすることを目指しています。これにより、GitHubやGitLabなどで使われるMarkdownと同じ感覚でJavadocを書くことができ、開発者のドキュメンテーション作成のハードルを大きく下げます。
注意点
- この機能はデフォルトで有効になります。もし従来のHTMLベースの記法を厳密に維持したい場合は、
javadoc
コマンドにオプション (--no-markdown
) を指定することで無効化できます。 - 既存のJavadocコメントは、ほとんどの場合、変更なしで正しくレンダリングされます。HTMLタグは引き続きサポートされるため、後方互換性は保たれています。
この変更は、Javaエコシステム全体のドキュメントの質を向上させ、より多くの開発者が積極的にドキュメンテーションを行う動機付けとなる、地味ながらも非常に影響の大きい改善です。
Part 3: パフォーマンスとGCの改善
Javaのパフォーマンスは、エンタープライズアプリケーションにとって生命線です。Java 24では、ガベージコレクタ(GC)の改善と、アプリケーション起動時間の短縮に関する重要なJEPが含まれています。
JEP 474: ZGC: Generational Mode by Default
ZGC (Z Garbage Collector) は、非常に低い停止時間(通常は1ミリ秒未満)を目標に設計された、スケーラブルな低レイテンシGCです。Java 15で本番利用可能(Production Ready)となり、特に大規模なヒープメモリを必要とし、かつ応答性が重要なアプリケーションで採用が進んでいます。
Java 21では、ZGCに「世代別GC(Generational GC)」の機能が導入されました。これにより、若いオブジェクト(生成されてからすぐに不要になるオブジェクト)の回収効率が大幅に向上し、スループットも改善しました。
背景と動機
これまでのZGCでは、世代別GCモードはオプションであり、有効にするには -XX:+ZGenerational
フラグを指定する必要がありました。デフォルトは非世代別のシングル・ジェネレーション・モードでした。
しかし、世代別ZGCのパフォーマンスと安定性が十分に証明され、ほとんどのワークロードでシングル・ジェネレーション・モードを上回る結果が得られるようになったため、このデフォルト設定を見直す時が来ました。
詳細な解説
JEP 474は、ZGCのデフォルトモードを世代別モードに変更するという、シンプルながらも影響の大きい変更です。
- Java 24以降:
-XX:+UseZGC
を指定してZGCを有効にすると、自動的に世代別ZGCが使われるようになります。 - 従来の挙動に戻したい場合: 明示的に
-XX:-ZGenerational
フラグを指定することで、従来のシングル・ジェネレーション・モードを使用することも可能です。
なぜこれが重要なのか?
多くのJavaアプリケーションでは、「世代別仮説(Generational Hypothesis)」、つまり「ほとんどのオブジェクトは生成後すぐに死ぬ」という経験則が成り立ちます。世代別GCは、この仮説に基づいて、ヒープを若い世代(Young Generation)と古い世代(Old Generation)に分割し、頻繁に発生する若いオブジェクトのガベージコレクション(Minor GC)を効率的に行うことで、GC全体のオーバーヘッドを削減します。
ZGCがデフォルトで世代別になることで、ユーザーは特別なチューニングを意識することなく、ZGCの持つ低レイテンシという利点に加えて、高いスループットと低いCPU/メモリオーバーヘッドという恩恵も享受できるようになります。これにより、ZGCがより幅広いアプリケーションにとって魅力的な選択肢となります。
JEP 475: G1: Parallel App-CDS Class Loading
G1 (Garbage-First) GCは、Java 9以降のデフォルトGCであり、スループットとレイテンシのバランスに優れた汎用的なGCです。一方、AppCDS (Application Class-Data Sharing) は、Javaアプリケーションの起動時間を短縮するための技術です。
AppCDSは、アプリケーションの初回実行時にクラス情報を解析・処理し、その結果を共有アーカイブファイルに保存します。2回目以降の起動時には、このアーカイブファイルをメモリに直接マッピングすることで、クラスのロードや検証にかかる時間を大幅に削減します。
背景と動機
AppCDSは非常に効果的な技術ですが、これまでの実装では、共有アーカイブからのクラスロード処理がシングルスレッドで行われていました。近年のマルチコアCPUの普及を考えると、ここにはパフォーマンス改善の余地がありました。特に、何千ものクラスを持つ大規模なアプリケーションやフレームワークでは、このシングルスレッドでのロードが起動時のボトルネックになる可能性がありました。
詳細な解説
JEP 475は、このボトルネックを解消するため、AppCDSの共有アーカイブからのクラスロード処理を並列化するものです。この改善は、デフォルトのGCであるG1で有効になります。
仕組み
- G1 GCを使用している場合、JVMは複数のスレッドを使って共有アーカイブからクラスをロードしようと試みます。
- これにより、マルチコアCPUのリソースを有効活用し、クラスロードのフェーズを高速化します。
- この機能はデフォルトで有効になり、ユーザーが特別な設定を行う必要はありません。
期待される効果
この改善により、特に以下のような環境で起動時間の短縮が期待されます。
- Spring BootやQuarkusなど、多数のクラスをロードするモダンなフレームワークを使用したアプリケーション。
- コンテナ環境やサーバーレス環境など、アプリケーションの起動/停止が頻繁に行われるシナリオ。
ベンチマークによると、アプリケーションの規模によっては起動時間が10%〜30%程度改善するケースも報告されており、Javaアプリケーション全体の応答性向上に寄与する重要な改善です。
Part 4: ツールとメンテナンス性の向上
Javaプラットフォームの健全性は、言語やAPIだけでなく、それを支えるツールやメンテナンス体制によっても保たれています。Java 24では、セキュリティ監視の強化や、将来に向けたプラットフォームの整理に関するJEPが含まれています。
JEP 470: JFR Event for Deserialization
デシリアライゼーション(Deserialization)は、バイトストリームからJavaオブジェクトを復元するプロセスであり、便利な機能である一方、セキュリティ上の脆弱性(いわゆる「デシリアライゼーション脆弱性」)の原因となりやすいことで知られています。悪意のある細工が施されたデータをデシリアライズすることで、任意のコードが実行されてしまう危険性があります。
背景と動機
このリスクを軽減するため、Javaではデシリアライゼーション・フィルタリング(JEP 290)などの対策が導入されてきました。しかし、アプリケーションが実際にどのようなクラスをデシリアライズしているのかを監視し、予期せぬ挙動を検知することは依然として困難でした。
詳細な解説
JEP 470は、この監視を容易にするため、オブジェクトのデシリアライゼーションが発生した際に、新しいJFR (JDK Flight Recorder) イベントを発生させる機能を追加します。
- 新しいイベント:
jdk.Deserialization
- 記録される情報: デシリアライズされたクラスの名前、オブジェクトグラフの深さ、参照の数、使用されたフィルタのステータスなど、詳細な情報が記録されます。
活用方法
JFRは、本番環境でも非常に低いオーバーヘッドでJVMの動作を記録できる強力なプロファイリングツールです。この新しいイベントを活用することで、システム管理者は以下のようなことが可能になります。
- セキュリティ監査: アプリケーションがどのクラスをデシリアライズしているかを把握し、許可リスト(allow-list)にないクラスが使われていないかを確認する。
- 異常検知: 通常とは異なるパターン(例えば、極端に深いオブジェクトグラフ)のデシリアライゼーションを検知し、攻撃の兆候を早期に発見する。
- フィルタのチューニング: デシリアライゼーション・フィルタを構成する際に、実際に使われているクラスの情報を元に、より厳密なルールを作成する。
この機能は、Javaアプリケーションのセキュリティをプロアクティブに強化するための、重要なツールとなります。
JEP 471: Deprecate the Windows 32-bit x86 Port for Removal
Javaは「Write Once, Run Anywhere」を掲げ、長年にわたり多種多様なプラットフォームをサポートしてきました。しかし、技術の進化に伴い、レガシーなプラットフォームのサポートを維持するコストは増大します。
背景と動機
Windowsの32ビット版(x86)は、現代のPC市場ではほとんど使われなくなりました。主要なOSベンダーやソフトウェア開発元も、64ビット版への移行を完了し、32ビット版のサポートを終了する傾向にあります。
OpenJDKコミュニティにとっても、このポートを維持・テストするための労力は大きく、そのリソースをより現代的で広く使われているプラットフォームの改善に振り向けた方が、エコシステム全体にとって有益であると判断されました。
詳細な解説
JEP 471は、Windows 32-bit x86ポートを「削除のために非推奨(Deprecate for Removal)」とします。
- Java 24: このポートでJDKをビルドしようとすると、警告が表示されるようになります。
- 将来のリリース: 将来的には、このポートのソースコードとビルドサポートがOpenJDKのリポジトリから完全に削除される予定です。
開発者への影響
ほとんどの開発者には影響はありません。現在、開発や本番環境でWindowsを使用している場合、そのほとんどは64ビット版です。もし、何らかの特別な理由でWindows 32ビット環境でJavaを実行する必要がある場合は、Java 23以前のLTSバージョン(Java 17や21など)を引き続き利用するか、64ビット環境への移行を計画する必要があります。
これは、Javaプラットフォームが未来を見据えて、リソースを最適化し、進化を続けていくための健全なプロセスの一環です。
まとめと今後の展望
Java 24は、短期サポートリリースながらも、Javaプラットフォームの進化における確かな一歩を示す、内容の濃いアップデートとなっています。主要なポイントを改めて振り返ってみましょう。
- 学習の簡素化 (JEP 477): 暗黙的クラスとインスタンスmainメソッドにより、Java初学者の学習曲線が劇的に緩やかになります。これはJavaコミュニティの裾野を広げるための戦略的な投資です。
- 開発者の生産性向上 (JEP 468, JEP 467): レコードの
with
式やJavadocのMarkdownサポートは、日々のコーディングやドキュメンテーション作業をより快適で効率的なものにします。 - パフォーマンスの深化 (JEP 474, JEP 475): デフォルトで世代別になるZGCや、並列化されたAppCDSクラスロードは、特別な設定なしでJavaアプリケーションの性能を引き上げ、特にクラウドネイティブ環境での競争力を高めます。
- セキュリティとメンテナンス性 (JEP 470, JEP 471): デシリアライゼーションの監視強化や、レガシープラットフォームの整理は、Javaを安全かつ持続可能なプラットフォームとして維持するための地道ながらも重要な取り組みです。
これらの機能は、それぞれが独立しているように見えながらも、「開発者体験の向上」「実行時パフォーマンスの最適化」「プラットフォームの現代化」という、Javaの進化を貫く大きなテーマに沿っています。
今後の展望
Javaの進化は止まりません。Java 24の先には、さらなるエキサイティングな機能が控えています。
- Project Valhalla: プリミティブクラスや値オブジェクトなど、Javaのメモリレイアウトを根本から見直し、パフォーマンスを飛躍的に向上させる可能性を秘めたプロジェクトが、徐々にプレビュー機能として姿を現し始めるでしょう。
- Project Leyden: Javaアプリケーションの起動時間をさらに短縮し、静的イメージを生成することを目指すプロジェクトも進行中です。
- パターンマッチングの進化:
switch
式やinstanceof
で使えるパターンは、今後さらに拡張され、より表現力豊かで安全なコード記述を可能にするでしょう。
6ヶ月ごとのリリースサイクルは、私たち開発者にとっても、常に新しい知識を学び続ける姿勢を求めます。しかしそれは、Javaというプラットフォームが、決して時代遅れになることなく、常にソフトウェア開発の最前線で戦うための力を与え続けてくれることの証でもあります。
ぜひJava 24をダウンロードして、その新機能をあなたの手で試し、未来のJava開発を体感してみてください。Javaの世界は、これからもますます面白くなっていきます。