Java 22 to 25 Features

Naveen AnamaneniUpdated · 5 min read

When a school redesigns its first-day welcome for new students, it doesn't change the subjects; it removes the confusing forms and long speeches that scare newcomers away. Several of the changes from Java 22 to Java 25 do exactly that for Java: a first program no longer needs public class and public static void main(String[] args), and a single import line can bring in a whole module. Alongside these friendlier changes came serious power tools: calling C libraries safely, custom stream operations, and faster startup. Java 25 (September 2025) is the LTS that collects them all, and it is the version this course is written for. In this lesson, you will get a quick reference to each release and a tour program that uses the Java 25 features.

What Each Release Added

ReleaseFinal featuresRead more
Java 22 (Mar 2024)Unnamed variables and patterns (_); Foreign Function and Memory API; launching programs made of several source files"Unnamed Variables and Patterns", "Foreign Function and Memory API in Java"
Java 23 (Sep 2024)Markdown documentation comments (///); generational mode becomes ZGC's default"Markdown Documentation Comments in Java"
Java 24 (Mar 2025)Stream gatherers; Class-File API; AOT class loading and linking; virtual threads no longer pinned by synchronized; quantum-resistant ML-KEM and ML-DSA; Security Manager permanently disabled"Stream Gatherers in Java", "Class-File API in Java", "AOT Class Loading and Caching in Java"
Java 25 (Sep 2025, LTS)Compact source files and instance main methods; module import declarations; flexible constructor bodies; scoped values; compact object headers; AOT one-step cache creation and method profiling; Key Derivation Function APIsee below

Java 25 in Detail

FeatureWhat it gives youRead more
Compact source files and instance main methodsvoid main() { IO.println("Hi"); } is a complete program"Compact Source Files and Instance Main Methods"
Module import declarationsimport module java.base; imports every exported package of a module"Module Import Declarations (Java 25)"
Flexible constructor bodiesStatements (validation, preparing arguments) before super(...) or this(...)"Flexible Constructor Bodies"
Scoped valuesShare an immutable value with a call tree and its threads; a safer ThreadLocal"Scoped Values in Java"
Compact object headersObject headers shrink from 12 to 8 bytes, saving heap (opt in with -XX:+UseCompactObjectHeaders)"Compact Object Headers in Java 25"
AOT cache in one step-XX:AOTCacheOutput trains and writes a startup cache in one run"AOT Class Loading and Caching in Java"

Still in preview or incubation in Java 25: structured concurrency, primitive types in patterns, stable values and the Vector API.

A Java 22 to 25 Tour

Let's see a compact source file that uses features from every release in this range. There is no class declaration around main: the file itself is the program.

Tour25.java▶ Try it
import module java.base;                                // 25: module import
 
record Fee(String student, int amount) {}
 
class LateFee extends RuntimeException {
    LateFee(int days) {
        String why = "late by " + days + " days";       // 25: before super
        super(why);
    }
}
 
static final ScopedValue<String> TERM = ScopedValue.newInstance();
 
void main() {                                           // 25: compact source
    List<Fee> fees = List.of(new Fee("Navika", 15000),
            new Fee("Srihitha", 14000), new Fee("Advitha", 16000));
 
    int count = 0;
    for (Fee _ : fees) count++;                         // 22: unnamed variable
    IO.println("fees: " + count);
 
    List<List<Fee>> batches = fees.stream()
            .gather(Gatherers.windowFixed(2))           // 24: gatherers
            .toList();
    IO.println("batches: " + batches.size());
 
    ScopedValue.where(TERM, "Term 2")                   // 25: scoped values
            .run(() -> IO.println("billing " + TERM.get()));
 
    try {
        throw new LateFee(3);
    } catch (LateFee e) {
        IO.println(e.getMessage());
    }
}
Output
fees: 3
batches: 2
billing Term 2
late by 3 days

Explanation:

  1. import module java.base; makes List, Gatherers and every other java.base class available without separate imports.
  2. void main() with no class around it is a compact source file. IO.println is the new, simpler console helper in java.lang.
  3. for (Fee _ : fees) says "I don't need the element", so no unused variable is named.
  4. Gatherers.windowFixed(2) groups the three fees into batches of two and one.
  5. ScopedValue.where(...).run(...) makes TERM readable only while that code runs.
  6. The LateFee constructor computes its message before calling super(why), which was a compile error before Java 25.

The LTS Releases at a Glance

LTSReleasedThree features to remember
Java 8Mar 2014Lambdas, streams, java.time
Java 11Sep 2018HttpClient, var in lambdas, String.strip/isBlank
Java 17Sep 2021Records, sealed classes, text blocks
Java 21Sep 2023Virtual threads, pattern matching for switch, sequenced collections
Java 25Sep 2025Compact source files, module imports, scoped values

Practice

  1. Easy: Write a compact source file Hello.java containing only void main() { IO.println("Hello, Navika Anamaneni"); } and run it with java Hello.java.
  2. Harder: From memory, write the LTS table above: release, year and three features each. Then check it against this lesson.

Quick check: Java 22 to 25

4 questions
1Which release made the FFM API final?
2What does import module java.base; do?
3Which Java 25 feature allows statements before super(...)?
4Which of these is still a preview in Java 25?

Key Takeaways

Was this tutorial helpful?

Lesson 565 of 578