JDK 16: The new features in Java 16

Due March 2021, the next Java upgrade targets primitive classes, sealed classes, records classes, a vector API, and ports for Windows on ARM64 and Alpine Linux

JDK 16: The new features in Java 16
Marina_Skoropadskaya / Getty Images

Java Development Kit (JDK) 16 has added warnings for value-based classes and a second preview of sealed classes as planned capabilities, joining a host of other features ranging from a foreign linker API to pattern matching to concurrent thread-stack processing for garbage collection.

JDK 16 will be the reference implementation of the version of standard Java set to follow JDK 15, which arrived September 15. A proposed release schedule has JDK 16 reaching rampdown phases on December 10 and January 14, 2021, followed by release candidates arriving February 4 and February 18, 2021. The production release is slated to be published March 16, 2021.

Fifteen proposals officially target JDK 16 as of December 1, 2020, while the warnings for value-based classes and the sealed classes preview remain in the “proposed for targeting” phase. The new capabilities coming to Java 16 include:

  • The warnings for value-based classes proposal designates the primitive wrapper classes as value-based and deprecates their constructors for removal, prompting new deprecation warnings. Warnings are provided about improper attempts to synchronize on instances of any value-based classes in the Java platform. Driving this effort is the Valhalla Project, which is pursuing a significant enhancement to the Java programming model in the form of primitive classes. Primitive classes declare instances to be identity-free and capable of inline or flattened representations, where instances can be copied freely between memory locations and encoded using values of instances’ fields. The design and implementation of primitive classes in Java is now sufficiently mature that the migration of certain classes of the Java platform to primitive classes can be anticipated in a future release. Candidates for migration are informally designated as value-based classes in API specifications.
  • Previously previewed in JDK 15, sealed classes and interfaces restrict which other classes and interfaces may extend or implement them. Goals of the plan include allowing the author of a class or interface to control the code responsible for implementing it, provide a more declarative way than access modifiers to restrict the use of a superclass, and support future directions in pattern matching by providing a foundation for analysis of patterns.
  • Strong encapsulation of JDK internals by default, except for critical internal APIs such as misc.Unsafe. Users can choose the relaxed strong encapsulation that has been the default since JDK 9. Goals of this proposal include improving the security and maintainability of the JDK, as part of Project Jigsaw, and encouraging developers to migrate from using internal elements to using standard APIs so that both developers and end users can update easily to future Java releases. This proposal does carry a primary risk that existing Java code will fail to run. Developers are encouraged to use the jdeps tool to identify code that depends on internal elements of the JDK and switch to standard replacements when available. Developers can use an existing release, such as JDK 11, to test existing code by using --illegal-access=warn to identify internal elements accessed via reflection, using --illegal-access=debug to pinpoint errant code, and testing with --illegal-access=deny.
  • Foreign linker API, offering statically typed, pure-Java access to native code. This API will be in an incubator stage in JDK 16. Together with the proposed foreign-memory access API, the foreign linker API will considerably simplify the otherwise error-prone process of binding to a native library. This plan is intended to replace JNI (Java Native Interface) with a superior pure-Java development model, to offer C support, and, over time, to be flexible enough to accommodate support for other platforms, such as 32-bit x86, and foreign functions written in languages other than C, such as C++. Performance should be better than or comparable to JNI.
  • Moving ZGC (Z Garbage Collector) thread-stack processing from safepoints to a concurrent phase. Goals of this plan include removing thread-stack processing from ZGC safepoints; making stack processing lazy, cooperative, concurrent, and incremental; removing all other per-thread root processing from ZGC safepoints; and providing a mechanism for other HotSpot VM subsystems to lazily process stacks. ZGC is intended to make GC pauses and scalability issues in HotSpot a thing of the past. So far, GC operations that scale with the size of the heap and the size of metaspace have been moved out of safepoint operations and into concurrent phases. These have included marking, relocation, reference processing, class unloading, and most root processing. The only activities still done in GC safepoints are a subset of root processing and a time-bounded marking termination operation. These roots have included Java thread stacks and other thread roots, with these roots being problematic because they scale with the number of threads. To move beyond the current situation, per-thread processing, including stack scanning, must be moved to a concurrent phase. With this plan, the throughput cost of the improved latency should be insignificant and the time spent inside ZGC safepoints on typical machines should be less than one millisecond.
  • An elastic metaspace capability, which returns unused HotSpot VM class metadata (metaspace) memory more promptly to the OS, reduces metaspace footprint and simplifies metaspace code to reduce maintenance costs. Metaspace has had issues with high off-heap memory use. The plan calls for replacing the existing memory allocator with a buddy-based allocation scheme, providing an algorithm to divide memory into partitions to satisfy memory requests. This approach has been used in places such as the Linux kernel and will make it practical to allocate memory in smaller chunks to reduce class-loader overhead. Fragmentation also will be reduced. In addition, the commitment of memory from the OS to memory management arenas will be done lazily, on demand, to reduce the footprint for loaders that start out with large arenas but do not use them immediately or might not use them to their full extent. To fully exploit the elasticity offered by buddy allocation, metaspace memory will be arranged into uniformly sized granules that can be committed and uncommitted independently of each other.
  • Enablement of C++ 14 language features, to allow the use of C++ 14 capabilities in JDK C++ source code and give specific guidance about which of these features may be used in HotSpot VM code. Through JDK 15, language features used by C++ code in the JDK have been limited to the C++98/03 language standards. With JDK 11, the source code was updated to support building with newer versions of the C++ standard. This includes being able to build with recent versions of compilers that support C++ 11/14 language features. This proposal does not propose any style or usage changes for C++ code that is used outside of HotSpot. But to take advantage of C++ language features, some build-time changes are required, depending on the platform compiler.
  • A vector API in an incubator stage, in which the JDK would be fitted with an incubator module, jdk.incubator.vector, to express vector computations that compile to optimal vector hardware instructions on supported CPU architectures, to achieve superior performance to equivalent scalar computations. The vector API provides a mechanism to write complex vector algorithms in Java, using pre-existing support in the HotSpot VM for vectorization but with a user model that makes vectorization more predictable and robust. Goals of the proposal include providing a clear and concise API to express a range of vector computations, being platform-agnostic by supporting multiple CPU architectures, and offering reliable runtime compilation and performance on x64 and AArch64 architectures. Graceful degradation also is a goal, in which a vector computation would degrade gracefully and still function if it cannot be fully expressed at runtime as a sequence of hardware vector instructions, either because an architecture does not support some instructions or another CPU architecture is not supported.
  • Porting the JDK to the Windows/AArch64 platform. With the release of new server-class and consumer AArch64 (ARM64) hardware, Windows/AArch64 has become an important platform due to demand. While the porting itself is already mostly complete, the focus of this proposal involves integration of the port into the mainline JDK repository.
  • Porting of the JDK to Alpine Linux and to other Linux distributions that use musl as their primary C library, on x64 and AArch64 architectures. Musl is a Linux implementation of the standard library functionality described in the ISO C and Posix standards. Alpine Linux is widely adopted in cloud deployments, microservices, and container environments due to its small image size. A Docker image for Linux is smaller than 6MB. Letting Java run out-of-the-box in such settings will allow Tomcat, Jetty, Spring, and other popular frameworks to work in these environments natively. By using jlink to reduce the size of the Java runtime, a user can create an even smaller image tailored to run a specific application.
  • Providing records classes that act as transparent carriers for immutable data. Records can be considered nominal tuples. Records was previewed in JDK 14 and JDK 15. This effort is in response to complaints that Java has been too verbose or has too much ceremony. Goals of the plan include devising an object-oriented construct that expresses a simple aggregation of values, helping developers focus on modeling immutable data rather than extensible behavior, automatically implementing data-driven methods such as equals and accessors, and preserving longstanding Java principles such as nominal typing.
  • The addition of Unix-domain socket channels, in which Unix-domain (AF_UNIX) socket support is added to the socket channel and server socket channel APIs in the nio.channels package. The plan also extends the inherited channel mechanism to support Unix-domain socket channels and server socket channels. Unix-domain sockets are used for inter-process communications on the same host. They are similar to TCP/IP sockets in most respects except that they are addressed by filesystem path names rather than IP addresses and port numbers. The goal of the new capability is to support all features of Unix-domain socket channels that are common across major Unix platforms and Windows. Unix-domain socket channels will behave the same as existing TCP/IP channels in terms of read/write behavior, connection setup, acceptance of incoming connections by servers, and multiplexing with other non-blocking selectable channels in a selector. Unix-domain sockets are more secure and more efficient than TCP/IP loopback connections for local, inter-process communications.
  • A foreign-memory access API, allowing Java programs to safely access foreign memory outside the Java heap. Previously incubated in both JDK 14 and JDK 15, the foreign-memory access API would be re-incubated in JDK 16, adding refinements. Changes have been made including a clearer separation of roles between the MemorySegment and MemoryAddresses interfaces. Goals of this proposal include providing a single API to operate on various kinds of foreign memory, including native, persistent, and managed heap memory. The API should not undermine the safety of the JVM. Motivating the proposal is that many Java programs access foreign memory, such as Ignite, Memcached, and MapDB. But the Java API does not provide a satisfactory solution for accessing foreign memory.
  • Pattern matching for the instanceof operator, which also was previewed in both JDK 14 and JDK 15. It would be finalized in JDK 16. Pattern matching allows common logic in a program, namely the conditional extraction of components from objects, to be expressed more concisely and safely.
  • Providing the jpackage tool for packaging self-contained Java applications. Introduced as an incubating tool in JDK 14, jpackage remained in incubation in JDK 15. With JDK 16, jpackage moves to production, supporting native package formats to give users a natural installation experience and allow launch-time parameters to be specified at packaging time. Formats include msi and exe on Windows, pkg and dmg on MacOS, and deb and rpm on Linux. The tool can be invoked directly from the command line or programmatically. The new packaging tool addresses a situation in which many Java applications need to be installed on native platforms in a first-class way, rather than being placed on the class path or module path. An installable package suitable for the native platform is needed.
  • Migration of OpenJDK source code repositories from Mercurial to Git. Driving this effort are advantages in version control system metadata size and available tools and hosting.
  • Migration to GitHub, related to the Mercurial-to-Git migration, with JDK 16 source code repositories to be on the popular code-sharing site. The transition to Git, GitHub, and Skara for the Mercurial JDK and JDK-sandbox was done on September 5 and is open for contributions.  

Early-access builds of JDK 16 for Linux, Windows, and MacOS can be found at jdk.java.net. Like JDK 15, JDK 16 will be a short-term release, supported for six months. JDK 17, due in September 2021, will be a long-term support (LTS) release that will receive several years of support. The current LTS release, JDK 11, was released in September 2018.

Copyright © 2020 IDG Communications, Inc.