posts
An overview of Java 23 features

An overview of Java 23 features

Jul 4, 2024
Dmitry Chuyko
13.4

JDK 23 entered a Rampdown Phase One on June 6, which means that the feature set is frozen. It’s high time we look at them more closely!

This release contains 12 Java Enhancement Proposals (JEPs) with new, enhanced, or deprecated features.

New features

JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)

JEP 455 aims to enhance pattern matching by enabling the developers to use primitive types in all pattern contexts, as well as with instanceof and switch, which will make Java patterns more expressive.

This feature also eliminates the risks of data loss due to unsafe casts. Up until now, instanceof type tests were limited to reference types, and there was no convenient way to check primitive values for safety of conversion. As a result, a primitive value could be silently converted without an exception. But now, the instanceof type test operator allows for primitive types. If a value can be safely converted, instanceof will report true. Otherwise, it will report false. 

JEP 467: Markdown Documentation Comments

JEP 467 will enable the developers to write JavaDoc documentation comments in Markdown. This will facilitate reading and writing API documentation comments. But this feature doesn’t aim to substitute HTML and JavaDoc tags, rather, it will allow using the combination of the three.

JEP 476: Module Import Declarations (Preview)

JEP 476 simplifies module imports by allowing the developers to import one module instead of explicitly importing its packages.

For instance, instead of

import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

Or

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

We will simply write

import module java.base

Enhanced features

JEP 466: Class-File API (Second Preview)

Class-File API was introduced in JDK 22 as a Preview feature. The goal is to equip the Java platform with a standard API for parsing, generating, and transforming class files. This API will evolve together with the class-file format and will enable the Java platform components and framework to rely on this API instead of third-party libraries.  

JEP 466 introduces a Second Preview of the feature with a few improvements based on the feedback.

JEP 469: Vector API (Eighth Incubator)

Vector API was first introduced in JDK 16. JEP 469 is the Eighth Incubator of the feature aiming to equip the developers with a way to write vector algorithms that reliably compile at runtime to optimal vector instructions on supported CPU architectures. This will provide better performance of scalar operations than with auto-vectorization.

JEP 469 re-incubates Vector API without changes.

JEP 473: Stream Gatherers (Second Preview)

Stream Gatherers were introduced in JDK 22 to enhance Stream API with the support for custom intermediate operations. Before Stream Gatherers, developers had to create separate classes or methods to use required logic in already existing intermediate operations. But this feature is not about adding more intermediate operations to the Stream API. Instead, developers get one new intermediate operation called Stream::gather(Gatherer) that allows for processing streams in a user-defined fashion.

JEP 473 re-previews the feature without changes.

JEP 474: ZGC: Generational Mode by Default

Generational mode for Z Garbage Collector was introduced in Java 21 with JEP 439. Before that, ZGC stored all objects together, and collected all objects at once. With generational mode, ZGC maintains separate collections for young and old objects, which means that it can collect young objects more frequently. So, the CPU overhead is lower, and the amount of released memory is bigger. 

JEP 474 makes generational mode default for ZGC. The non-generational mode, which is inferior to generational one in most cases, will be deprecated in this release and removed in future releases.

JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)

This feature was introduced in JDK 21 as a Preview. It enables programmers who just started learning Java to write simple single-class programs without enterprise-grade features, and then extend these programs as their knowledge grows.

But what are Implicitly Declared Classes and Instance Main Methods?

Instance main methods are not static and need not be public and have a String[] parameter. Thus, the standard Hello, World! program can be simplified to:

class HelloWorld {
    void main() {
        System.out.println("Hello, World!");
    }
}

Implicitly declared classes have only a default zero-parameter constructor, reside in an unnamed package, and cannot be referenced by name. Every implicit class must contain a main method and represent a standalone program. As a result, the Hello, World! Code can be further simplified to:

void main() {
    System.out.println("Hello, World!");
}

JEP 477 introduces a Third Preview of the feature with two major improvements:

Implicitly declared classes automatically import three static methods from a new top-level class java.io.IO:

  • public static void println(Object obj)
  • public static void print(Object obj)
  • public static String readln(String prompt)

This way, students don’t have to deal with System.in and System.out and all related concepts. So, a simple interactive program will look like that:

void main() {
    String name = readln("Please enter your name: ");
    print("Pleased to meet you, ");
    println(name);
}

Another addition is the automatic import of the java.base module. So the APIs in the commonly used packages will be allowed for the use in the body of an implicitly declared class as if they were imported. 

JEP 480: Structured Concurrency (Third Preview)

Structured concurrency is aimed at providing the developers with a more reliable and transparent way of writing concurrent code. The approach is based on a principle of a single unit of work, i.e., if the tasks are split into subtasks, then subtasks should return to the parent task’s code block. This way,

  • The task-subtask relationship will be demonstrated clearly in the code struction, which enhances observability;
  • If any of the subtasks fail or a thread running the tasks is interrupted before join(), other subtasks are canceled, which promotes code reliability.

Structured concurrency was first introduced in JDK 19. JEP 480 re-previews the feature without changes. 

JEP 481: Scoped Values (Third Preview)

Scoped values were first introduced in JDK 20. Scoped values are a more robust and memory-efficient alternative to thread-local variables, especially when used together with virtual threads. Scoped values enable a method to share immutable data with its callees within a thread and with child threads.

A scoped value is available only until the method that called it finishes, which should prevent long-term memory leaks associated with thread-local variables, whose values are retained for the thread lifetime or until the remove method is called). 

Note that scoped values should be used for one-way transmission of immutable data. They are not suitable for two-way transmission.

JEP 481 re-previews the feature with one change: the removal of the ScopedValue.getWhere method, which is substituted with a new functional interface that allows JVM to deduce whether a checked exception might be thrown. 

JEP 482: Flexible Constructor Bodies (Second Preview)

This feature was introduced in JDK 22 as JEP 447: Statements before super(...). Its goal is to reduce code verbosity and complexity by enabling the developers to place statements before an explicit constructor invocation. Note that the feature won’t break the natural top-down order initialization.

JEP 482 introduces a Second Preview of the feature with new name and one substantial change: a constructor body can now initialize fields in the same class before explicitly invoking a constructor. As a result, a constructor in a superclass won’t be able to execute code which sees the default field value in the subclass.

Deprecated features

JEP 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal

The aim of the sun.misc.Unsafe class has been to perform low-level operations in the JDK as it contains methods for accessing on-heap and off-heap memory. These methods can help to increase the performance in some specific scenarios, but only if exhaustive safe checks are performed along the way. Otherwise, the use of these methods may lead to unexpected application behavior, JVM crashes, or performance deterioration. Unfortunately, many libraries use sun.misc.Unsafe, but not all of them perform due safe checks.

To address this issue, two replacement APIs were introduced: Variable Handles for accessing on-heap memory and Foreign Function & Memory API for the off-heap memory. These API’s are inherently more stable and reliable and should be used instead of sun.misc.Unsafe. 

Thanks to the introduction of these APIs, it is not possible to deprecate sun.misc.Unsafe with JEP 471 for removal in future releases.

Get the performance of newer Java versions without migration

Early-access builds of JDK 23 are available for you to experiment with. Although Java 23 is a non-LTS release, it is worth trying out new features, especially if you are planning to use the next LTS version due 2025.

What if some of your services run on older JDK versions 8 or 11, and upgrading is off the table for now? You can get the performance of JDK 17 without migration with Liberica JDK Performance Edition! It couples JDK 8 or 11 and JVM 17 and enables you to boost the application performance without major code changes.

Contact us if you would like to know more about the solution.

Contact us

Subcribe to our newsletter

figure

Read the industry news, receive solutions to your problems, and find the ways to save money.

Further reading