Java 23 Features: A Deep Dive Into the Newest Enhancements
Dive into this overview of significant changes in Java 23, focusing on the most notable JEPs (JDK Enhancement Proposals).
Join the DZone community and get the full member experience.
Join For FreeAs Java continues to evolve, each new release aims to introduce features that improve the language’s performance, usability, and flexibility. By adopting this release, you can stay ahead of the curve and prepare for when these features become stable in future LTS versions.
In this article, I will give you a quick overview of significant changes in Java 23, focusing on the most notable JEPs (JDK Enhancement Proposals). Those interested in previous changes can check out my earlier article on Java 21 features, and you can also read Dariusz Wawer’s older piece with a detailed description of Java 17 features (along with a comparison to Java 8).
For code examples, you have to add --enable-preview
flag to your compiler args.
Primitive Types in Patterns, instanceof
, and switch
(Preview)
Primitive types have always been integral to Java, but handling them in patterns, instanceof
, and switch
constructs was limited. JEP 455 aims to extend pattern matching and the switch
statement to support primitive types.
static String processInput(Object obj) {
return switch (obj) {
case Integer i -> "Integer value: %s".formatted(i);
case Double d -> "Double value: %s".formatted(d);
default -> "Unknown type";
};
}
public static void main(String[] args) {
System.out.println(processInput(10)); // Integer value: 10
System.out.println(processInput(5.5)); // Double value: 5.5
}
This enhancement allows developers to write cleaner and more concise code.
Class-File API (Second Preview)
Java's class file format is crucial for bytecode manipulation and tool development. JEP 466 introduces the second preview of a new Class-File API, simplifying access to and manipulation of Java class files without requiring developers to rely on third-party libraries like ASM or BCEL.
This API will greatly benefit those working on frameworks, compilers, or tools that need to inspect or modify class files. With its straightforward design, it enhances flexibility while keeping developers closer to Java’s native mechanisms. You can find a simple example of interacting with a new API below:
public static void main(String[] args) throws IOException {
ClassFile classFile = ClassFile.of();
ClassModel model=classFile.parse(Paths.get("/home/ExampleClass.class"));
System.out.println("Class Name: " + model.thisClass());
// Class Name: 7 java23/ExampleClass
model.methods().forEach(
method -> System.out.println(" - " + method.methodName()));
//- <init>
//- sayHello
}
Stream Gatherers (Second Preview)
Another preview feature brings very nice enhancements to the Java Stream API. As JEP473 documentation states, the main goals are to make stream pipelines more flexible and expressive and allow custom intermediate operations to manipulate streams of infinite size. Below are a few examples of built-in gathers operations:
Stream.of("A", "B", "C", "D", "E")
.gather(Gatherers.fold(() -> "", (a, b) -> a + b))
.forEach(System.out::println);
//ABCDE
Stream.of("A", "B", "C", "D")
.gather(Gatherers.windowFixed(2))
.forEach(System.out::println);
//[A, B]
//[C, D]
Of course, there is the possibility of creating your gatherers. To do that, you just have to implement the java.util.stream.Gatherer
interface.
Scoped Values (Third Preview)
JEP 481 introduces scoped values, which are an alternative to thread-local variables. They provide a mechanism for sharing values within a specific scope, making it easier to work with multi-threaded applications. Let’s dive into code example:
public class Jep481ScopedValues {
private static ScopedValue<String> X = ScopedValue.newInstance();
public static void main(String[] args) {
foo();
}
static void foo() {
ScopedValue.runWhere(X, "foo", () -> bar());
}
static void bar() {
System.out.println("Printing X from bar(): " + X.get());
ScopedValue.runWhere(X, "bar", () -> baz());
System.out.println("Printing X from bar(): " + X.get());
}
static void baz() {
System.out.println("Printing X from baz(): " + X.get());
}
}
Output:
Printing X from bar(): foo
Printing X from baz(): bar
Printing X from bar(): foo
Flexible Constructor Bodies (Second Preview)
JEP 482 revisits constructor flexibility in Java. Traditionally, constructor bodies in Java were limited in how they could be structured and how exceptions could be handled. This JEP introduces more flexibility, allowing developers to write more complex initialization logic within constructors, which enhances control over object creation.
public class Java481FlexibleConstructors extends BigInteger {
Java481FlexibleConstructors(long value) throws Exception {
if (value < 0) throw new Exception("Invalid value");
//that wasn’t possible before
System.out.println("Initialized with value: " + value);
super(String.valueOf(value));
}
}
Other Notable Features in Java 23
In addition to the JEPs I've already covered, Java 23 introduces several other enhancements worth mentioning:
- Performance improvements (JEP 474: ZGC Generational Mode by Default): Java 23 optimizes the Z Garbage Collector by enabling its generational mode by default. This feature improves the efficiency of memory management, particularly for applications with long-running processes, by segregating young and old objects in the heap to enhance garbage collection performance
- Security updates (JEP 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal): This update deprecates certain memory-access methods in
sun.misc.Unsafe
that were widely used for direct memory manipulation, enhancing the security of the platform. - Library enhancements (JEP 467: Markdown Documentation Comments): JEP 467 introduces support for Markdown in Javadoc comments. This feature allows developers to write better-formatted and more readable documentation using Markdown syntax within their code comments, improving both internal and external documentation practices
- Module system improvements (JEP 476: Module Import Declarations): JEP 476 adds the ability to use import module declarations in Java source files. This simplifies module management, especially in multi-module projects, by allowing developers to import entire modules, not just individual classes or packages.
Summary
Java continues to evolve, and version 23 brings a wealth of improvements that will enhance the developer experience, from better handling of primitive types in pattern matching to more flexible constructors and advanced stream processing. Be sure to explore the changes and start incorporating them into your development workflow – as they will probably soon turn from preview features to core ones.
Published at DZone with permission of Arkadiusz Rosloniec. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments