Toll Free:

1800 889 7020

New Features in Java 23: A Comparison with Java 22

Java continues to evolve, and with each version, Java developers gain access to more powerful tools, enhanced performance, and improved syntax. In this article, we will explore the new features of Java 23 and compare them with its predecessor, Java 22.

What’s New in Java 23?

Java 23 introduces several exciting features that aim to improve the language and runtime environment.

Pattern Matching for Switch (Improved):

This feature was introduced in Java 17 and received more refinements in Java 23. The developers can now write more readable and compact code by using Java pattern matching for switch statements for more complex types, including records and arrays. This enhancement reduces the need for excessive if-else logic. Here is a simple code example:

sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double length, double width) implements Shape {}
public class Main {
public static void main(String[] args) {
Shape shape = new Circle(5.0);
String result = switch (shape) {
case Circle c -> "Circle with radius: " + c.radius();
case Rectangle r -> "Rectangle with length: " + r.length() + " and width: " + r.width();
};
System.out.println(result);
}
}

Here, we use pattern matching in a switch statement to handle different shapes (circle, rectangle) and extract their attributes directly without casting or writing additional if-else blocks.

Project Loom – Virtual Threads:

Project Loom has been one of the most anticipated features. In Java 23, virtual threads are more stable and closer to production use. These lightweight threads are designed to handle massive concurrency, simplifying multithreading by reducing the resource overhead and complexity associated with traditional threads. Here is a simple code example:

public class VirtualThreadExample {
public static void main(String[] args) {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(1, 10).forEach(i -> {
executor.submit(() -> {
System.out.println("Thread " + i + " is running");
});
});
}
}
}

In this example, we create virtual threads using the new Executors.newVirtualThreadPerTaskExecutor() method. These threads are lightweight and designed for concurrent tasks.

Record Patterns:

Java introduced records to create immutable data classes with minimal boilerplate code. In Java 23, record patterns allow developers to destructure record types directly in pattern-matching expressions, making the syntax more concise and functional. Here is a simple code example:

record Point(int x, int y) {}
public class RecordPatternExample {
public static void main(String[] args) {
Object obj = new Point(3, 4);
if (obj instanceof Point(int x, int y)) {
System.out.println("Point with coordinates: " + x + ", " + y);
}
}
}

This code demonstrates how we can destructure a record type directly in an instanceof check, making the code more concise by automatically extracting the values of x and y from the Point object.

Improved Garbage Collection (GC):

Java 23 has made further improvements to its garbage collection algorithms, especially focusing on low-latency use cases. ZGC (Z Garbage Collector) and G1 (Garbage-First) collectors have seen performance tweaks, reducing application pauses, which is crucial for real-time and large-scale applications. Here is a simple code snippet:

// Example flag usage for enabling ZGC
// Run the JVM with the following option to enable ZGC:
// java -XX:+UseZGC MyApp.java

ZGC is designed for low-latency applications, and using this JVM flag enables the Z Garbage Collector. In large-scale or real-time applications, reducing pause times is critical, and ZGC provides better performance for these use cases.

Sequenced Collections API:

Java 23 introduces a new API to handle sequenced collections, such as lists, sets, and other ordered data structures. This API allows developers to handle common operations like reversing or processing data in sequential order more easily. Here is a simple code example:

List numbers = List.of(1, 2, 3, 4, 5);
var reversed = numbers.reversed(); // New method in Sequenced Collections API
reversed.forEach(System.out::println);

This code showcases the new reversed() method in the Sequenced Collections API, which reverses the order of elements in the list without the need for manually reversing them.

Foreign Function and Memory API (Enhanced):

The Foreign Function and Memory API, which allows Java programs to call native libraries and handle off-heap memory, is more robust in Java 23. The API has improved safety mechanisms, making it easier to write performant and safe code when working with non-Java memory. Here is a simple code example:

import jdk.incubator.foreign.*;
public class ForeignMemoryAccess {
public static void main(String[] args) {
try (MemorySegment segment = MemorySegment.allocateNative(1024)) {
MemoryAddress address = segment.address();
System.out.println("Allocated memory at address: " + address);
}
}
}

In this example, we use the Foreign Function and Memory API to allocate native memory (off-heap). The memory segment is automatically deallocated when it is no longer needed, thanks to the try-with-resources block.

Markdown Documentation Comments

Java 23 allows developers to write documentation comments using Markdown syntax and in that way it makes easier to create well-formatted and readable API documentation.

Example:

Markdown Documentation Comments

The use of triple slashes (`///`) denotes a Markdown comment, allowing for rich text formatting within the code documentation.

Module Import Declarations (Preview)

This feature simplifies the reuse of modular libraries by allowing developers to import all packages exported by a module with a single declaration.

Example:

Module important

If we import the entire module, then all its exported packages will become accessible, and it will reduce the need for multiple import statements.

Flexible Constructor Bodies (Second Preview)

This enhancement allows constructors to include statements such as validations or initializations before calling the `super()` or `this()`, providing greater flexibility in object construction.

Example:

Flexible Constructor Bodies

Here, the constructor validates the input and initializes the field before invoking a method from the superclass and by this way it enhances control over the initialization process.

Stream Gatherers (Second Preview)

This feature enhances the Stream API by allowing the creation of custom intermediate operations, and by this way it enables more flexible and expressive data processing pipelines.

Example:

Stream Gatherers

In this example, `windowFixed(2)` creates a sliding window over the stream elements of A, B, C, D and DEF, and then it groups them into pairs, which are then processed together.

Structured Concurrency (Third Preview)

Structured concurrency introduces a new API that treats groups of related tasks running in different threads as a single unit of work and hence it simplifys error handling and cancellation.

Example:

Structured Concurrency

Java 23 Performance-Oriented Features:

Java 23 introduces various features which enhance performance and developer efficiency compared to Java 17 and Java 21. Below I have explained some of the key optimizations i.e. accompanied by complex examples:

1. Vector API Enhancements

In Java 23, the Vector API, incubated in earlier Java versions has been further refined. It enables developers to perform vector computations that compile at runtime to optimal vector instructions on supported CPU architectures and this leads to significant performance improvements over scalar computations.

Example:

Vector API Enhancements

In this example, the Vector API allows simultaneous processing of multiple float values and leverages SIMD (Single Instruction, Multiple Data) capabilities of modern CPUs. This results in performance gains over traditional element-wise operations.

2. ZGC: Generational Mode by Default

Java 23 enables the Generational Mode in the Z Garbage Collector (ZGC) by default. This mode segregates objects into young and old generations and this optimizes garbage collection processes and reduce the pause times, which enhances application throughput.

Example:

ZGC

In this scenario, the Generational Mode efficiently manages short-lived `String` objects and long-lived `byte` arrays, thereby reducing garbage collection overhead and improving performance.

3. Primitive Types in Patterns, `instanceof`, and `switch` (Preview)

Java 23 extends pattern matching to support primitive types in `instanceof` and `switch` constructs. This enhancement reduces the need for boxing and unboxing operations and this really leads to more efficient and readable code.

Example:

Primitive Types in Patterns

This feature streamlines type checking and casting, reducing boilerplate code and potential performance costs associated with boxing.

4. Structured Concurrency (Third Preview)

Structured concurrency in Java 23 introduces a structured approach to managing multiple threads, enhancing reliability and maintainability of concurrent code. It ensures that related tasks are executed within a defined scope and hence it actually simplifys error handling and resource management.

Example:

Structured Concurrency

Comparison Between Java 23 and Java 22 Features

FeatureJava 22Java 23
Pattern Matching for SwitchIntroduced in earlier versions with limited support for certain types and less flexibility in handling more complex conditions like nested types.Enhanced with better type handling, including arrays, records, and sealed classes. Developers can now write more concise and readable switch expressions, simplifying conditional logic and removing the need for excessive if-else constructs.
Project Loom – Virtual ThreadsProvided experimental support for virtual threads, aimed at lightweight thread management, but was not stable for production environments. Focused on reducing the overhead of thread management in highly concurrent applications.Virtual threads are more stable and closer to production readiness, offering improved performance and better scalability for multi-threaded applications. They allow for more efficient concurrent operations with minimal resource usage.
Record PatternsSupported basic record types, but pattern matching with records was limited in scope. Could not fully destructure record types, requiring manual extraction of data members.Expanded support for record patterns, enabling complete deconstruction within switch expressions and if statements. This simplifies working with immutable data, making pattern matching with records more powerful and expressive.
Garbage Collection (GC)Continued improvements to ZGC and G1 collectors, providing low-latency options with better memory management. Some performance tweaks were introduced, but issues with long pause times persisted in certain use cases.Further optimizations in ZGC and G1, focusing on reducing pause times and enhancing throughput for applications with real-time requirements. Java 23 provides better garbage collection performance for both small and large-scale applications.
Sequenced CollectionsNo specific API for handling sequenced collections in Java 22, requiring developers to manually implement reverse operations or sequential data processing in ordered collections.Java 23 introduces the Sequenced Collections API, simplifying operations on ordered collections like lists and sets. It provides native methods for reversing collections, accessing elements in order, and performing sequential operations.
Foreign Function and Memory APIProvided as an incubator feature, enabling early use cases for native code interoperability and off-heap memory handling. However, it lacked comprehensive safety mechanisms and was experimental.Java 23 enhances this API with improved safety features and better performance. The API allows for more stable and secure interactions with native libraries and off-heap memory, making it more suitable for production applications.

Conclusion

Java 23 is a significant upgrade over Java 22, especially for developers working with concurrent applications, performance-sensitive systems, or foreign libraries. The refinements in pattern matching, virtual threads, and garbage collection make it a powerful tool for modern Java development services. For developers already using Java 22, upgrading to Java 23 will offer performance boosts and more concise syntax, particularly with pattern matching and record handling. For more details, you can visit the official release pages for Java 22 and Java 23.

Harsh Savani

Harsh Savani is an accomplished Business Analyst with a strong track record of bridging the gap between business needs and technical solutions. With 15+ of experience, Harsh excels in gathering and analyzing requirements, creating detailed documentation, and collaborating with cross-functional teams to deliver impactful projects. Skilled in data analysis, process optimization, and stakeholder management, Harsh is committed to driving operational efficiency and aligning business objectives with strategic solutions.

Scroll to Top