Skip to content

Repository files navigation

Java 21 LTS vs Java 25 LTS 機能比較サンプル

Java 21(前 LTS)と Java 25(最新 LTS)の新機能・改善点をコードで体感するためのサンプルプロジェクトです。 同じ機能を両バージョンで実装し、Preview → Finalized の変化API の変更を実際に動かして確認できます。


プロジェクト構成

java_sample/
├── java21/          # Java 21 LTS で動くデモ (前 LTS)
└── java25/          # Java 25 LTS で動くデモ (最新 LTS)

各モジュールに同名または対応するデモクラスが存在し、バージョン間の差分をコードレベルで比較できます。


前提条件

ツール バージョン 備考
Gradle 8.14 以上 gradlew スクリプト同梱のため個別インストール不要
JDK 21 / 25 インストール不要 — Gradle が自動でダウンロード(Foojay Toolchain Resolver

JDK の自動ダウンロードについて settings.gradle.ktsfoojay-resolver-convention プラグインを設定済みです。 初回実行時に JDK 21・25 が ~/.gradle/jdks/ に自動取得されます。


実行方法

# Java 21 LTS デモを実行
./gradlew :java21:run

# Java 25 LTS デモを実行
./gradlew :java25:run

# 両バージョンを続けて実行して比較
./gradlew :java21:run :java25:run

機能差分一覧

Java 21 (前 LTS) に存在する機能

# 機能 Java 21 Java 25 JEP
Virtual Threads ✅ Finalized (ピン留めあり) ✅ ピン留め解消 444 / 491
Scoped Values ⚠️ 1st Preview Finalized 446 → 506
Structured Concurrency ⚠️ 1st Preview ⚠️ 5th Preview API大変更 453 → 505
Record Patterns ✅ Finalized 変化なし 440
Pattern Matching for switch ✅ Finalized 変化なし 441
Sequenced Collections ✅ Finalized 変化なし 431

Java 25 (最新 LTS) で追加された機能

# 機能 Java 21 Java 25 JEP
Stream Gatherers ❌ なし Finalized 485
Flexible Constructor Bodies ❌ なし Finalized 513
Module Import Declarations ❌ なし Finalized 511

✅ = --enable-preview 不要 / ⚠️ = --enable-preview 必要 / ❌ = 未サポート


各機能の解説

① Virtual Threads

JEP 444 (Java 21 Finalized) → JEP 491 (Java 24 改善)

Java 21 で Finalized になった Virtual Threads。ただし Java 21 では synchronized ブロック内でキャリアスレッドへの「ピン留め」が発生し、スループットが低下する問題があった。Java 24 (JEP 491) でこの問題が解消され、Java 25 でも改善が継続。

バージョン synchronized 内での挙動
Java 21 ピン留め発生 → ReentrantLock を推奨
Java 25 ピン留め解消 → synchronized も安全
// Java 21: ReentrantLock を使うのが推奨だった
var lock = new ReentrantLock();
executor.submit(() -> {
    lock.lock();
    try { doWork(); } finally { lock.unlock(); }
});

// Java 25: synchronized でも安全 (JEP 491)
executor.submit(() -> {
    synchronized (MONITOR) { doWork(); } // ピン留めなし
});

📄 VirtualThreadsDemo.java(java21 / java25 でコメントが異なる


② Scoped Values

JEP 446(Java 21: 1st Preview) → JEP 506(Java 25: Finalized)

スレッドローカル変数の安全な代替。Java 21 では 1st Preview として登場し、4 バージョンの改良を経て Java 25 で Finalized。

比較項目 ThreadLocal ScopedValue
可変性 ミュータブル イミュータブル
スコープ 不明確 明示的(where-run)
コスト 相対的に高い 低い
private static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();

ScopedValue.where(CURRENT_USER, "Alice").run(() -> {
    System.out.println(CURRENT_USER.get()); // → Alice
    ScopedValue.where(CURRENT_USER, "Admin").run(() ->
        System.out.println(CURRENT_USER.get()) // → Admin
    );
    System.out.println(CURRENT_USER.get()); // → Alice(元に戻る)
});

Java 21 と Java 25 のコードは全く同じ。 違いは java21/build.gradle.kts--enable-preview フラグのみ。

📄 ScopedValuesDemo.java(java21 / java25 共通)


③ Structured Concurrency(API大幅変更!)

JEP 453(Java 21: 1st Preview) → JEP 505(Java 25: 5th Preview)

関連する並行タスクをひとつのスコープで管理する API。 Java 25 で API が Breaking Change を含む大幅刷新。

Java 21 API(旧)

// コンストラクタでポリシーを指定
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    var user  = scope.fork(() -> fetchUser());
    var order = scope.fork(() -> fetchOrder());
    scope.join().throwIfFailed(); // ← 手動でエラーチェック
    System.out.println(user.get() + order.get());
}

// 最速結果を採用
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
    scope.fork(() -> fetchFromPrimary());
    scope.fork(() -> fetchFromCache());
    scope.join();
    String result = scope.result(); // ← 別メソッドで結果取得
}

Java 25 API(新)

// static factory method + Joiner パターン
try (var scope = StructuredTaskScope.open(
        StructuredTaskScope.Joiner.<String>allSuccessfulOrThrow())) {
    scope.fork(() -> fetchUser());
    scope.fork(() -> fetchOrder());
    scope.join()                    // ← join() が Stream<Subtask> を返す
         .map(Subtask::get)
         .forEach(System.out::println);
}

// 最速結果を採用
try (var scope = StructuredTaskScope.open(
        StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
    scope.fork(() -> fetchFromPrimary());
    scope.fork(() -> fetchFromCache());
    String result = scope.join();   // ← join() が直接結果を返す
}

📄 StructuredConcurrencyDemo.java(java21 / java25 で異なる実装)← 最も差分が大きい


④ Record Patterns

JEP 440 / Java 21 Finalized

instanceofswitch でレコードのコンポーネントを直接分解できる。ネストしたレコードも一度に分解可能。Java 25 でも変化なし。

record Point(int x, int y) {}
record Line(Point start, Point end) {}

// ネストした Record の分解
if (line instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {
    System.out.println("Line: (" + x1 + "," + y1 + ") → (" + x2 + "," + y2 + ")");
}

📄 RecordPatternsDemo.java(java21 のみ ─ Java 21 固有デモ)


⑤ Pattern Matching for switch

JEP 441 / Java 21 Finalized

switch での型パターン・null ハンドリング・guard 条件 (when) が Finalized。Java 25 でも変化なし。

String desc = switch (obj) {
    case Integer i when i < 0 -> "負の整数: " + i;
    case Integer i             -> "正の整数: " + i;
    case String s              -> "文字列: " + s;
    case null                  -> "null!";
    default                    -> "その他";
};

📄 PatternMatchingSwitchDemo.java(java21 のみ ─ Java 21 固有デモ)


⑥ Sequenced Collections

JEP 431 / Java 21 Finalized

ListSetMapgetFirst()getLast()addFirst()reversed() など統一 API を追加。Java 25 でも変化なし。

var list = new ArrayList<>(List.of("A", "B", "C"));
list.getFirst();   // → "A"  (Java 21 以前: list.get(0))
list.getLast();    // → "C"  (Java 21 以前: list.get(list.size() - 1))
list.reversed();   // → ["C", "B", "A"]

📄 SequencedCollectionsDemo.java(java21 のみ ─ Java 21 固有デモ)


⑦ Stream Gatherers

JEP 485 / Java 24 Finalized(Java 21 にはない)

Stream に任意の中間操作を追加できる拡張 API。windowFixedscanfold などの組み込み Gatherer を提供。

// 3つずつのグループに分割
List.of(1, 2, 3, 4, 5, 6, 7)
    .stream()
    .gather(Gatherers.windowFixed(3))
    .forEach(System.out::println);
// → [1, 2, 3]  [4, 5, 6]  [7]

📄 StreamGatherersDemo.java(java25 のみ)


⑧ Flexible Constructor Bodies

JEP 513 / Java 25 Finalized(Java 21 にはない)

コンストラクタ内で super() / this() の前にコードを書けるようになった。引数の検証・変換をコンストラクタ内で完結できる。

class Circle extends Shape {
    Circle(double radius) {
        double validated = Math.abs(radius); // ← super() より前に検証!
        super("circle", validated);
    }
}

📄 FlexibleConstructorDemo.java(java25 のみ)


⑨ Module Import Declarations

JEP 511 / Java 25 Finalized(Java 21 にはない)

import module <モジュール名>; 1行でモジュール全体をインポートできる。

// Java 25 Finalized
import module java.base; // ← これ1行で java.base の全型が使える!

public class Example {
    List<String> list = List.of("Java", "25");  // import なしで使える
    Map<String, Integer> map = new HashMap<>();
}

📄 ModuleImportDemo.java / ModuleImportExample.java(java25 のみ)


ビルド設定の比較(重要)

java21/build.gradle.kts

tasks.withType<JavaCompile> {
    options.compilerArgs.addAll(listOf("--enable-preview"))
    options.release = 21
}
// --enable-preview が必要な機能:
//   ScopedValues (JEP 446 - 1st Preview)
//   Structured Concurrency (JEP 453 - 1st Preview)
// --enable-preview 不要:
//   Virtual Threads, Record Patterns, Pattern Matching for switch, Sequenced Collections

java25/build.gradle.kts

tasks.withType<JavaCompile> {
    options.compilerArgs.addAll(listOf("--enable-preview"))
    options.release = 25
}
// まだ --enable-preview 必要:
//   Structured Concurrency (JEP 505 - 5th Preview)
// --enable-preview 不要 (Finalized):
//   Scoped Values, Stream Gatherers, Flexible Constructor Bodies, Module Import Declarations

技術スタック

項目 内容
言語 Java 21 (LTS) / Java 25 (LTS)
ビルドツール Gradle 8.14(Kotlin DSL)
JDK 管理 Gradle Toolchain + Foojay Resolver(自動ダウンロード)

参考リンク

About

java25のバージョンアップ確認

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages