JDK 22 entered the Rampdown Phase Two on January 18, an excellent occasion to peek at the JEPs awaiting us in this feature release!
JDK 22 is the first release after LTS JDK 21, but the community is buzzing with activity: the feature version includes 12 JEPs with new and enhanced functionality.
Table of Contents
- JEPs targeted to JDK 22
- JEP 423: Region Pinning for G1
- JEP 447: Statements before super(...) (Preview)
- JEP 454: Foreign Function & Memory API
- JEP 456: Unnamed Variables & Patterns
- JEP 457: Class-File API (Preview)
- JEP 458: Launch Multi-File Source-Code Programs
- JEP 459: String Templates (Second Preview)
- JEP 460: Vector API (Seventh Incubator)
- JEP 461: Stream Gatherers (Preview)
- JEP 462: Structured Concurrency (Second Preview)
- JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)
- JEP 464: Scoped Values (Second Preview)
- Get the performance of newer JDK versions without migration!
JEPs targeted to JDK 22
JEP 423: Region Pinning for G1
JEP 423 aims to reduce latency during garbage collection by not disabling G1 GC in the presence of Java Native Interface (JNI) critical regions.
JNI uses pointers for relevant Java objects to work with unmanaged programming languages. The memory regions where these objects reside are considered critical regions, and these objects, when in use, should not be moved during garbage collection.
Consequently, G1 GC disables garbage collection when a thread is in a critical region, meaning it must wait until no threads are in critical regions when garbage collection is triggered. It may lead to significant latency (up to several minutes), OutOfMemory errors, and VM shutdown.
As G1 GC could already pin certain regions to their memory locations during major collections and perform collection without touching them, this JEP extends this functionality and enables G1 GC to pin regions during minor and major collections. As a result:
- pinned regions in young generation will be promoted to old generation, and pinned regions in old generation will not be evacuated, and consequently,
- garbage collection can be performed normally even in the presence of critical regions.
JEP 447: Statements before super(...) (Preview)
Thanks to Java’s natural polymorphism, classes can conveniently extend other classes, inheriting their functionality and adding their own. For this to work, Java constructors must be initialized from the top down, i.e., the constructor in the superclass must first initialize the fields declared in this class, and only after that can the constructor in the subclass run. To guarantee this behavior, Java requires in the constructor body, to place explicit invocation of another constructor as the first statement, like this:
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
super(value);
if (value <= 0)
throw new IllegalArgumentException("non-positive value");
}
}
However, this sometimes leads to excessive verbosity and code complexity. For instance, in a snippet above, we need to add an additional method if we want to validate the constructor fields before invoking the constructor of a superclass:
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
super(verifyPositive(value));
}
private static long verifyPositive(long value) {
if (value <= 0)
throw new IllegalArgumentException("non-positive value");
return value;
}
}
JEP 447 enables the developers to place statements that do not reference the instance being created before an explicit constructor invocation. So the snippet above can be transformed into:
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
if (value <= 0)
throw new IllegalArgumentException("non-positive value");
super(value);
}
}
This feature doesn’t break the top-down initialization or require changes to the JVM. However, it makes initialization more flexible, thus promoting more laconic and maintainable code.
JEP 454: Foreign Function & Memory API
JEP 454 finalizes the Foreign Function & Memory API that enables Java programs to interoperate with code outside of the JVM safely and reliably, without the dangers of JNI.
The JEP includes the following improvements:
- a new linker option enabling clients to pass heap segments to downcall method handles;
- a new
Enable-Native-Access
manifest attribute for JAR-files, which allows code in executable JAR files to call restricted methods without the--enable-native-access command-line
option; - a new possibility for clients to build C-language function descriptors programmatically;
- enhanced support for variable-length arrays in native memory;
- support for arbitrary charsets for native strings.
JEP 456: Unnamed Variables & Patterns
JEP 456 finalizes without changes the Unnamed Variables & Patterns feature introduced in JDK LTS 21. This functionality allows to substitute with the underscore character _ the following elements:
- the unnecessary type and name of a record component in pattern matching,
- variables that must be declared but will not be used.
This increases the readability and maintainability of the Java code significantly.
JEP 457: Class-File API (Preview)
Class files are the cornerstone of the Java platform. Java includes several libraries for parsing, generating, and transforming class files, and frameworks usually bundle a class-file library.
However, the class-file format evolves rapidly due to the six-month Java release cadence. So, the framework developers cannot keep up with the changes in the Java platform and update their class-file libraries promptly, which may lead to errors and incorrect behavior.
Even Java cannot level up with the class-format changes because it uses third-party libraries for class-file processing, whose updates are also delayed.
JEP 457 introduces a standard class-file API, which will evolve together with the class-file format. This way, Java components will not be dependent on third-party libraries anymore, and the framework developers will be able to support class files from new JDK versions automatically.
JEP 458: Launch Multi-File Source-Code Programs
JEP 458 enhances the java application launcher and enables the developers to run Java programs supplied as multiple files of source code. This will facilitate work at the initial stages of development because developers don’t have to create a project configuration for a build tool to compile several .java files, i.e., they can skip the project setup stage until they have a clear understanding of a project structure and a complex workload. This way, the traditional edit/build/run cycle shortens to edit/run.
JEP 459: String Templates (Second Preview)
JEP 459 is the Second Preview of the String Templates feature introduced in JDK 21. The feature enables the developers to concatenate literal text with embedded expressions, thus
- facilitating the expression of strings that contain values computed at run time by reducing the boilerplate code and
- eliminating the risks of string interpolation.
The Second Preview is aimed at gathering feedback from the developers and includes only one minor change related to the types of template expressions.
JEP 460: Vector API (Seventh Incubator)
JEP 460 introduces the Seventh Incubator of a Vector API, which helps increase the performance of vector computations that compile to optimal vector instructions at runtime. If you would like to know more about this feature, We discussed the performance gains related to Vector API in our article dedicated to JDK 17.
The Seventh Incubator encompasses several bug fixes and improvements, including the support for vector access with heap MemorySegments, backed by an array of any primitive element type.
JEP 461: Stream Gatherers (Preview)
The Stream API was first introduced in Java 8. With its help, streams (value sequences) can be processed sequentially or in parallel, using a range of intermediate and terminal operations: filtering, mapping, etc. The existing set of intermediate operations is rather limited, albeit efficient. However, adding more operations to the Stream API will unjustifiably complicate it.
JEP 461 introduces a new feature to enhance the Stream API with custom intermediate operations so that developers can process the streams as they see fit. This is made possible with a new intermediate stream operation, Stream::gather(Gatherer)
, which applies special gatherers to stream elements defined by a user. Gatherers are an instance of the java.util.stream.Gatherer
interface. They transform elements of a stream relying on its four functions:
- An initializer provides an object maintaining private state while processing stream elements.
- An integrator integrates a new element from the input stream
- A combiner can evaluate the gatherer sequentially or in parallel in case of parallel input streams.
- A finisher is invoked when there are no more input elements left to consume.
The new feature will allow the developers to create more flexible and expressive stream pipelines, avoiding verbosity and enhancing code readability.
JEP 462: Structured Concurrency (Second Preview)
Structured concurrency API is aimed at improving observability and management of multi-threaded code. It is especially useful for developers working with virtual threads whose amount can reach tens of thousands. The API treats related subtasks executed in different threads as a family belonging to a single unit of work (task). Each subtask is forked and then joined in the parent task’s code block. This way, the task can coordinate subtasks and monitor them for failures, thus eliminating the common risks related to cancellation and shutdown and promoting reliability of concurrent applications.
JEP 462 introduces a Second Preview of the API without any changes with the aim to gather additional feedback from developers.
JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)
JEP 463 introduces the Second Preview of a feature included in JDK 21 (JEP 445: Unnamed Classes and Instance Main Methods). The functionality enables the developers who just started learning Java to write simple programs and then extend them as their knowledge grows. For instance, a simple Hello World program without complicated but unnecessary for novices features will look like this:
class HelloWorld {
void main() {
System.out.println("Hello, World!");
}
}
The Second Preview brings several important changes to the functionality, including the different name:
- Simplified classes declaration: a source file without an enclosing class declaration is said to implicitly declare a class with a name chosen by the host system.
- Facilitated selection of a main method to be invoked: if there is a main method with a
String[]
parameter, it is invoked. Otherwise, the main method without parameters is invoked.
JEP 464: Scoped Values (Second Preview)
Scoped values is another feature aimed at enhancing the multi-threaded programming in Java. It enables the developers to share immutable data within and across threads and should be preferred to thread-local variables as it promotes better reliability, smaller complexity, and improved footprint.
JEP 464 introduces a Second Preview of scoped values without changes to gather additional feedback.
Get the performance of newer JDK versions without migration!
A corporate stack usually incorporates several JDK versions. While you may consider migrating newer services to the latest and greatest release, some of your services may still run on JDK 8 or 11. If you would like to boost their performance without upgrading the Java version, BellSoft engineers developed a solution for you — Liberica JDK Performance Edition, which couples JDK 11 and JVM 17. What is more, if you are already subscribed to Liberica JDK support, this functionality comes free of charge!