Posts

Liberica JDK 16: more developer-friendly, more powerful

Mar 19, 2021
Alex Belokrylov
14.6

Today we welcome JDK 16, the last version of the Java Development Kit before the stable, long-term support (LTS) release. Contrary to what some people would assume, it’s not a “placeholder” title. Version 16 is a standalone JDK and features 17 new capabilities — with native support for Alpine Linux integrated by BellSoft.

There were 3085 bug fixes, backports and sub-tasks performed, including 21 issues resolved by the BellSoft team. OpenJFX also got 58 bugs resolved prior to this release. Here’s the official JDK 16 fix ratio from Oracle:

In the following paragraphs, we’ll explore our personal favorites in JDK 16, ranked by their value to user-end Java developers.

1. Records (JEP 395), Sealed Classes (JEP 397), and Pattern Matching for instanceof (JEP 394)

The combination of these three features is an entirely new step toward algebraic data types in Java™. They are essentially the next iteration of Project Amber. First previewed back in JDK 14 (by JEP 395), records act as transparent carriers for immutable data. They answer the language’s verboseness and stringent nature (which sometimes leads to boilerplate). Sealed classes got a second preview in this version; they were proposed by JEP 360. A class or an interface is sealed with the sealed modifier to its declaration and restricts which other classes or interfaces may extend it. Lastly, pattern matching, previewed by JEP 305 only for the instanceof operator, for the time being, allows common logic in a program to be expressed more concisely and safely. The work here is still in progress, and we’re patiently waiting for the entirety of Pattern matching to be delivered in some future JDK versions.

Overall, records + sealed classes + pattern matching enhance Java and make it even more convenient to describe algorithms. Here’s a nice example:

// sealed requires --enable-preview --source 16

sealed interface Expr permits SumExpr, NegExpr, IntExpr { }

record SumExpr(Expr left, Expr right) implements Expr { }

record NegExpr(Expr expr) implements Expr { }

record IntExpr(int value) implements Expr { }

static int eval(Expr e) {

 // Let's wait for pattern matching for switch

 // Let's wait for records deconstruction

 if (e instanceof SumExpr se) return eval(se.left) + eval(se.right);

 if (e instanceof NegExpr ne) return -eval(ne.expr);

 if (e instanceof IntExpr ie) return ie.value;

 return 0; // Should become unnecessary (not yet in recent EA)

}

2. Vector API (JEP 338)

One of the most meaningful features in this release, albeit still in incubating form (jdk.incubator.vector). It’s about enabling advanced developers to code cross-platform computations leveraging hardware data parallelism. Vector API explicitly deals with the following dark silicon instructions that JVM and JDK weren’t able to leverage previously:

  • SIMD;
  • AVX on x86;
  • NEON and SVE on ARM.

The goals for this JEP were to develop a clear and concise API that is platform-agnostic, performing reliably and degrading gracefully. It was also meant to be maximally expressive and portable, abstracting away from different peculiarities of instructions in architecture. The resulting Vector API allows fast mathematical calculations in Java. It is an out-of-the-box functionality running natively both on Intel-based and ARM-based devices.

In the future, we expect Vector API to benefit from value types once they are ready and roll out with Project Valhalla.

3. Alpine Linux Port (JEP 386)

This JEP was the most exciting for our team because we have been among its creators. Now that the Alpine Linux port has met upstream, everyone can start building tiny containers with a lightweight OS image and your JDK of choice. Of course, we recommend Liberica JDK since it has been optimized for this platform for quite some time!

Read more about the benefits of Alpine Linux native support and our engineering work on JEP 386 in last year’s article “Optimizing Java Microservices with the smallest container on the market”.

Or watch this interview with Dmitry Chuyko, Senior Performance Architect at BellSoft, where he talks at length about the port and its meaning for Java development.


4. Windows/AArch64 Port (JEP 388)

Another solid contribution from an OpenJDK vendor, this time the Java development team at Microsoft. The Windows port for ARM is extended from the Linux/AArch64 port (JEP 237), has got optimized intrinsics from JEP 315, and is finally ready for production.

Needless to say, this feature has been highly expected in the community. Its integration to the mainline JDK will lead to more available Windows-based binaries for ARM 64-bit processors.

5. Packaging Tool (JEP 392)

Until recently, the recommended way to use the Java language on a system was to have a single shared runtime on which to run all Java programs. This was meant to save space on your hard drive and bandwidth by downloading only the bytecode instead of the full runtime. Unfortunately, Java applications were then delivered as JARs, which meant: you first needed to install the runtime, then the JAR, and somehow add the JAR to the runtime.

This is not enough for the modern application developer. They must deliver quality UX with installables suited for the user platform. All programs should behave in a familiar manner (like when double-clicking on a package launches a wizard on Windows or drag-and-dropping a file into the Application folder installs it on macOS).

The utility (proposed initially by JEP 343 in JDK 14) builds on the legacy javapackager from Oracle JavaFX and introduces the production-ready jpackage tool. It allows developers to create their own self-contained Java applications with runtime included. The feature is supported for all operating systems and their native packaging formats: msi and exe on Windows, pkg and dmg on macOS, and deb and rpm on Linux.

Would you like to learn how these new features can help your Java software but feel uncertain about switching to JDK 16? No need to worry! Let our expert engineers guide you through the migration process and receive High-Powered Support from a major OpenJDK contributor.

6. Elastic Metaspace (JEP 387)

Even since the JDK project moved to open source, the community has been teaching garbage collectors how to return unused buffer memory to the operating system. It was implemented in JDK 12 for the default G1. Then, two new low-latency GCs, scalable ZGC (first integrated into JDK 11) and low-time-pause Shenandoah GC (first integrated into JDK 12), changed from experimental features to product features in JDK 15. These collectors attempt to tackle the common problem of too long full GC pauses and increase the overall responsiveness in the cloud.

This JEP is about working with the internal Java structures so that they also give back some of the consumed resources. Previously, when the memory of metaspace collecting HotSpot class metadata was no longer needed, it was returned to the JVM. But the JVM itself did not return it to the OS promptly. Now, with metaspace elasticity improved, this memory gets allocated in smaller chunks, while also decreasing class-loader overhead and fragmentation. It means returning unused memory faster, reducing footprint, and cutting down on maintenance costs.

We thank our colleagues at SAP for the valuable contribution to OpenJDK!

7. Enable C++14 Language Features (JEP 347), Migrate from Mercurial to Git (JEP 357), and Migrate to GitHub (JEP 369)

Not all improvements manifest themselves in the binaries used for app development. Some JEPs are geared toward the developers of Java as the programming language. However, the rest will benefit indirectly since these changes make it easier to get work done for the community and deliver enhancements faster.

We’re glad that the migration to Git is complete, that we can use C++ features, and that GitHub’s modern development and code review tools are finally available to all contributors to the JDK core. Much thanks to the Oracle team and Oracle-led Project Skara.

8. Strongly Encapsulate JDK Internals by Default (JEP 396)

The creators of Java provide a set of APIs that developers are welcome to apply in their production and testing. There is an unvoiced agreement that the future versions of the JDK will continue having this toolset. In order to deliver those APIs, the maintainers of the platform have internal elements of the JDK, which weren’t initially meant for external purposes.

However, many end-user Java applications appear to be tied to the internal JDK APIs and not public ones. Ever since JDK 9, the efforts to hide them from public use have been implemented within Project Jigsaw.

Developers are encouraged to migrate from using internal elements to using standard APIs in JDK 16 with this strong encapsulation: access to packages that existed in JDK 8 and do not contain critical internal APIs will be denied. Migration to 16 thus may be harmful because some libraries (e.g., Lombok) are not prepared for this change — and it’s been four years after JDK 9!

What should you do if your software depends on APIs from this list of internal packages no longer open by default?

  1. Rewrite the application without referring to these elements;
  2. While you’re at it, use the internals with special –illegal-access keys described in the JEP.

Overall, this switch will improve the security and maintainability of Java SE implementations in general, and the JDK in particular.

Custom Liberica JDK features

We could not leave this major release without introducing something special for our clients.

  • Discovery API v1 is still the actual stable version. All new Liberica JDK binaries are available with the same API.
  • Spring Boot container default. A perk that has actually been around before this release: When building a standard Docker container in Spring with the Maven plugin, it automatically picks Liberica JDK as a base runtime image.
  • Continued support for AOT and Graal JIT. These experimental features have been deprecated in Oracle’s OpenJDK builds and are now subject to removal. We at BellSoft are advocates of the native image technology and recommend compiling native images with Liberica NIK to avoid any errors.

The OpenJDK community is stronger and closer than ever in bringing efficiency to software engineers across the world. Now let’s buckle up and get ready for JDK 17, due to roll out this September!

To download all the Liberica JDK 16 builds, click here or the button below.

Subcribe to our newsletter

figure

Read the industry news, receive solutions to your problems, and find the ways to save money.

Further reading