An Overview of the features with Code Examples
Java 23, released in September 2024, continues the tradition of introducing improvements that make the language more efficient and developer-friendly. The release includes enhancements like ZGC’s generational mode, deprecation of unsafe memory-access methods, structured concurrency, and new capabilities in JavaDoc. This article walks you through these changes with practical code examples to help you integrate them into your development process.
Permanent Features in Java 23
Markdown Support in JavaDoc (JEP 467)
Before going any too technical, let us start with the cool Markdown doc, Java 23 introduces Markdown support to JavaDoc, making it easier to create well-formatted and readable documentation. You can now use Markdown syntax directly in your JavaDoc comments, simplifying the creation of code examples, headings, and lists.
Here’s how it works in practice:
/**
* This class demonstrates the new JavaDoc Markdown support.
*
* # Example Usage
* ```
* MyClass myClass = new MyClass();
* myClass.performAction();
* ```
*
* **Note:** This uses Markdown for formatting.
*/
public class MyClass {
public void performAction() {
System.out.println("Action performed");
}
ZGC Generational Mode by Default (JEP 474)
Generational garbage collection algorithms are designed with the understanding that most objects die young (i.e., they are created and then quickly discarded). By focusing on these objects, the collector can perform garbage collection more frequently on the young generation while doing less frequent collections of the old generation, which can lead to overall improvements in performance.
With the introduction of Java 23, the Z Garbage Collector (ZGC) has transitioned to using generational mode by default. The previously optional ZGenerational flag has now been set to true by default, which enhances performance by better managing memory for short-lived objects. The non-generational mode is deprecated, and any attempt to enable it will issue warnings regarding its deprecation.
Here’s how the new behavior manifests based on the command-line arguments:
- Using
-XX:+UseZGC
activates Generational ZGC without any additional flags. - Specifying
-XX:+UseZGC -XX:+ZGenerational
will also activate Generational ZGC but will issue a warning indicating that the ZGenerational option is deprecated. - If you use
-XX:+UseZGC -XX:-ZGenerational
, it falls back to the non-generational mode, triggering warnings about its deprecation and potential removal.
To utilize the new default generational ZGC, you can run your application with the following command:
java -XX:+UseZGC -Xmx4G -Xms4G MyJavaApp
For more detailed information on JEP 474 and other enhancements in Java 23, refer to the official documentation at openjdk.org.
Deprecation of sun.misc.Unsafe
Memory-Access Methods (JEP 471)
Java Unsafe class library is a powerful but risky feature that provides low-level operations typically not accessible through standard Java APIs. It allows developers to manipulate memory directly, perform operations such as allocating and freeing memory, and bypass certain Java safety features. While Unsafe can improve performance and enable advanced functionalities, it can lead to unpredictable behavior and security vulnerabilities if not used carefully for that reason there was a plan for a while to deprecate it.
JEP 471 marks the next step in deprecating the unsafe memory-access methods in the sun.misc.Unsafe
package. Java is moving towards more secure memory manipulation techniques, encouraging the use of safer APIs like VarHandle
and MemorySegment
. These APIs provide similar functionality but with built-in safety mechanisms that reduce the risk of memory corruption or leaks.
Using VarHandle
for Safe Memory Access
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class SafeMemoryAccess {
private static int myValue;
private static VarHandle MY_VALUE_HANDLE;
static {
try {
MY_VALUE_HANDLE = MethodHandles.lookup().findStaticVarHandle(SafeMemoryAccess.class, "myValue", int.class);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static void updateValue(int newValue) {
MY_VALUE_HANDLE.set(newValue);
}
public static int getValue() {
return (int) MY_VALUE_HANDLE.get();
}
}
Using MemorySegment
for Safe Memory Manipulation
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
public class SafeMemorySegmentAccess {
public static void main(String[] args) {
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
MemorySegment segment = MemorySegment.allocateNative(4, scope);
segment.setAtIndex(int.class, 0, 42);
int value = segment.getAtIndex(int.class, 0);
System.out.println("Value from memory segment: " + value);
}
}
}
For more details, see the full JEP 471 documentation on openjdk.org.
Preview Features in Java 23
Primitive Types in Patterns and Switch (JEP 455)
Java 23 expands the pattern matching feature introduced in earlier versions to support primitive types. This makes it easier to work with primitive values in switch
and instanceof
statements, allowing more concise and expressive code.
Developers can now simplify testing and conversion between primitive types like int
, byte
, and float
. Instead of verbose syntax, they can use:
instead of :
if (i >= -128 && i <= 127) {
byte b = (byte)i;
... b ...
}
We can simply do :
if (i instanceof byte b) {
... b ...
}
This enhancement improves code readability and minimizes errors from lossy conversions.
Moreover, switch statements can directly process primitive type patterns, enhancing clarity:
switch (x.getStatus()) {
case 0 -> System.out.println("OK");
case int i -> System.out.println("Unknown status: " + i);
}
JEP 455 also improves record patterns’ compatibility with primitive types, enabling automatic type narrowing without data loss:
if (json instanceof JsonObject(var map)
&& map.get("name") instanceof JsonString(String n)
&& map.get("age") instanceof JsonNumber(double a)) {
int age = (int)a; // Simplified with JEP 455
}
This feature makes pattern matching more versatile by supporting primitive data types directly in switch statements.
Structured Concurrency (JEP 428)
Structured Concurrency aims to simplify working with multiple tasks across different threads. It improves observability and error handling in complex multi-threaded applications.
Using Structured Concurrency
import java.util.concurrent.*;
public class StructuredConcurrencyExample {
public static void main(String[] args) {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> task1 = scope.fork(() -> "Task 1 result");
Future<String> task2 = scope.fork(() -> "Task 2 result");
scope.join();
scope.throwIfFailed();
System.out.println(task1.resultNow());
System.out.println(task2.resultNow());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
This preview feature enhances concurrency by ensuring that all tasks are handled in a structured manner, reducing the likelihood of unhandled exceptions or resource leaks.
Class-File API (JEP 466)
The Class-File API, in its second preview, provides a standard way to parse and manipulate Java class files, which is particularly useful for developers working on bytecode manipulation.
Code Example: Using the Class-File API
import jdk.classfile.ClassFile;
import java.io.IOException;
import java.nio.file.*;
public class ClassFileExample {
public static void main(String[] args) throws IOException {
Path classFilePath = Paths.get("MyClass.class");
byte[] classFileBytes = Files.readAllBytes(classFilePath);
ClassFile classFile = ClassFile.read(classFileBytes);
System.out.println("Class Name: " + classFile.getThisClassName());
}
}
This API allows you to safely inspect Java class files without resorting to third-party libraries.
Java 23 brings a host of new features and preview capabilities that help developers write cleaner, safer, and more efficient code. From improvements in garbage collection to better concurrency mechanisms and safer memory management, these updates push Java forward. Be sure to explore these features in your own projects, whether you’re looking to optimize performance or simplify multi-threading tasks.
Stay tuned for all java updates , subscribe to Byte-code.org
Leave a Reply