Java 23

Release Information

  • Release Date: September 17, 2024
  • Support Type: Non-LTS (6-month support)
  • End of Support: March 2025 (superseded by Java 24)
  • JEPs: 12 enhancements

Highlights: 2 final features, 8 preview features, 1 incubator, 1 deprecation

Final Features

ZGC: Generational Mode by Default (JEP 474) - FINAL

ZGC now uses generational garbage collection by default.

What changed:

# Before (Java 22): Non-generational by default
java -XX:+UseZGC MyApp

# After (Java 23): Generational by default
java -XX:+UseZGC MyApp  # Uses generational ZGC

# Opt-out to non-generational
java -XX:+UseZGC -XX:-ZGenerational MyApp

Why generational?

Generational hypothesis: Most objects die young.

Benefits:

  • Lower CPU overhead (10-20% reduction)
  • Better throughput (similar latency)
  • Smaller heap footprint

Performance comparison:

ModeCPU OverheadPause TimeThroughput
Non-generationalHigher<1msLower
GenerationalLower<1msHigher

When to use ZGC generational:

  • Applications with high allocation rates
  • Large heaps (multiple GB)
  • Need both low latency AND good throughput

Markdown Documentation Comments (JEP 467) - FINAL

Write JavaDoc using Markdown instead of HTML.

Old (HTML in JavaDoc):

/**
 * Computes the sum of two numbers.
 * <p>
 * <b>Example:</b>
 * <pre>{@code
 * int result = add(2, 3); // returns 5
 * }</pre>
 *
 * @param a the first number
 * @param b the second number
 * @return the sum of a and b
 */
public int add(int a, int b) {
    return a + b;
}

New (Markdown):

/// Computes the sum of two numbers.
///
/// **Example:**
/// ```java
/// int result = add(2, 3); // returns 5
/// ```
///
/// @param a the first number
/// @param b the second number
/// @return the sum of a and b
public int add(int a, int b) {
    return a + b;
}

Markdown features:

  • Headers: ## Header, ### Subheader
  • Bold/Italic: **bold**, *italic*
  • Code blocks: ```java ... ```
  • Lists: - item 1, 1. numbered
  • Links: [text](https://example.com)
  • Tables: Markdown table syntax

Mixed mode:

/**
 * Traditional JavaDoc comment (HTML)
 */

///
/// Markdown comment (Markdown syntax)
///

Preview Features

Primitive Types in Patterns (JEP 455) - Preview

Pattern matching now works with primitive types.

Example:

static void printType(Object obj) {
    switch (obj) {
        case Integer i -> System.out.println("Integer: " + i);
        case Long l -> System.out.println("Long: " + l);
        case int i -> System.out.println("int: " + i);  // ✨ NEW: primitive
        case long l -> System.out.println("long: " + l); // ✨ NEW: primitive
        case String s -> System.out.println("String: " + s);
        default -> System.out.println("Unknown");
    }
}

Widening conversions:

static void process(Number num) {
    switch (num) {
        case byte b -> System.out.println("byte: " + b);
        case short s -> System.out.println("short: " + s);
        case int i -> System.out.println("int: " + i);
        case long l -> System.out.println("long: " + l);
        case float f -> System.out.println("float: " + f);
        case double d -> System.out.println("double: " + d);
        default -> System.out.println("Other number");
    }
}

Module Import Declarations (JEP 476) - Preview

Import all packages from a module in one statement.

Old (verbose):

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Stream;
import java.util.stream.Collectors;
// ... many more imports

New (concise):

import module java.base; // Imports all java.util.*, java.io.*, etc.

Real-world example:

import module java.base;
import module java.sql;

public class DatabaseExample {
    public void process() {
        // All java.base and java.sql classes available
        List<String> names = new ArrayList<>();
        try (Connection conn = DriverManager.getConnection(url)) {
            // ...
        }
    }
}

Benefits:

  • Fewer import statements
  • Clearer module dependencies
  • Easier refactoring

Class-File API (JEP 466) - Second Preview

Standard API for parsing, generating, and transforming Java class files.

Use cases:

  • Bytecode manipulation frameworks (ASM, ByteBuddy alternatives)
  • Code coverage tools
  • Profilers and instrumentation
  • Build tools

Example (read class file):

import java.lang.classfile.*;

Path classFile = Path.of("MyClass.class");
ClassModel model = ClassFile.of().parse(classFile);

System.out.println("Class: " + model.thisClass().asInternalName());
for (MethodModel method : model.methods()) {
    System.out.println("Method: " + method.methodName());
}

Transform class file:

ClassFile cf = ClassFile.of();
byte[] transformedBytes = cf.transform(originalBytes, (cb, ce) -> {
    if (ce instanceof MethodModel mm) {
        cb.transformMethod(mm, (mb, me) -> {
            // Add logging to each method
            mb.with(me);
        });
    } else {
        cb.with(ce);
    }
});

Stream Gatherers (JEP 473) - Second Preview

Enhanced custom stream operations.

New gatherers:

// distinctBy: Remove duplicates by key
List<Person> people = ...;
List<Person> uniqueByName = people.stream()
    .gather(Gatherers.distinctBy(Person::name))
    .toList();

// mapConcurrent: Parallel transformation
List<String> urls = ...;
List<Data> results = urls.stream()
    .gather(Gatherers.mapConcurrent(url -> fetchData(url)))
    .toList();

Continued Preview Features

Structured Concurrency (JEP 480) - Third Preview

Refinements to task scoping.

New: Timeout support:

try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    scope.fork(() -> fetchUserData());
    scope.fork(() -> fetchOrderData());

    scope.joinUntil(Instant.now().plusSeconds(5)); // Timeout after 5s
    scope.throwIfFailed();
}

Scoped Values (JEP 481) - Third Preview

Improved thread-local alternative.

Enhanced API:

private static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();

void handleRequest(User user) {
    ScopedValue.runWhere(CURRENT_USER, user, () -> {
        processRequest();
        // CURRENT_USER available in all nested calls
    });
}

Flexible Constructor Bodies (JEP 482) - Second Preview

More flexibility in constructor initialization.

Example:

class ValidatedPoint {
    final int x, y;

    public ValidatedPoint(int x, int y) {
        // Validation before field initialization
        if (x < 0 || y < 0) {
            throw new IllegalArgumentException("Coordinates must be non-negative");
        }

        // Transform before super()
        int normalizedX = normalize(x);
        int normalizedY = normalize(y);

        this.x = normalizedX;
        this.y = normalizedY;
    }
}

Implicitly Declared Classes (JEP 477) - Third Preview

Simplified Java for beginners.

Example:

// Entire program
void main() {
    String name = readLine("Enter name: ");
    println("Hello, " + name + "!");
}

Incubator Features

Vector API (JEP 469) - Eighth Incubator

Continued SIMD API refinement.

Deprecations

Deprecate sun.misc.Unsafe Memory-Access Methods (JEP 471)

Memory access methods in sun.misc.Unsafe deprecated for removal.

Reason: FFM API is now standard (safer and more efficient)

Migration:

// ❌ OLD: sun.misc.Unsafe
Unsafe unsafe = Unsafe.getUnsafe();
long address = unsafe.allocateMemory(1024);
unsafe.putInt(address, 42);
unsafe.freeMemory(address);

// ✅ NEW: Foreign Function & Memory API
try (Arena arena = Arena.ofConfined()) {
    MemorySegment segment = arena.allocate(1024);
    segment.set(ValueLayout.JAVA_INT, 0, 42);
} // Automatic cleanup

Prepare to Restrict JNI Use (JEP 472)

Warnings when using JNI (preparation for future restrictions).

Goal: Encourage migration to FFM API

Migration Considerations

Upgrading from Java 21 LTS:

  1. ZGC: Generational mode now default (better performance)
  2. Markdown JavaDoc: Can simplify documentation writing
  3. Module imports: Reduce import boilerplate
  4. Unsafe deprecation: Plan migration to FFM API
  5. Preview features: Most features require --enable-preview

Enable preview features:

java --enable-preview --source 23 MyApp.java

Compatibility: Binary compatible with Java 21

Related Topics

References

Sources:

Official OpenJDK JEPs:

Last updated