JDk 17

2021 10 02 head

I truly love the new release rhythm of the Java ecosystem. Every six months a new JDK is delivered. Being able to use new features every six months is awesome.

The new release JDK 17 [3] is the next long term support LTS release. The migration overhead is held to a minimum thanks to the incredible backward compatibility. The early-access builds give you more than enough opportunities and time to migrate all your applications on time.

The new features greatly simplify existing code and tremendously increase code legibility.

Algebraic data types are now complete with the official release of records and sealed types. The advanced pattern matching constructs enhance the functional programming capabilities in Java.

Polishing of the functional programming approach improved my source code quite stupendously.

Why Should You Upgrade?

Be honest. It is more a question of when, rather than if you will upgrade.

Why should you actually upgrade your application?

  • Every Java version, even minor versions offer performance benefits, but also security fixes,

  • Other useful extras that make your application more robust and better maintainable are often part of a new release,

  • It includes cool features. For instance, the recently released Java records, sealed types, or the pattern matching functionality,

  • Reduce attack surface by updating project dependencies proactively,

  • Reduce technical debt and most importantly, prepare your project for the new and dynamic modern Java world,

  • Take advantage of performance improvements on new JVM version,

  • Take advantage from improvements of Java as programming language,

  • Sleep better by having a more secure, efficient and quality product.

I have noticed that a lot of applications are still on Java 8. Java 8 was released in March 2014. Businesses often say, we do not have time to invest now. They are saying we prefer to accumulate technical debt.

Non-experts often estimate that it is a lot of work, maybe even weeks or months of work to upgrade from one LTS version to the next LTS version of Java. It is seen as a challenge difficult to estimate, and is automatically postponed. That is not a good approach.

If you are still on Java 8, the licensing situation is may be problematic. Like all JDKs past their end of public updates, you now have to pay for support, or you must use a free OpenJDK 8u build which

  1. only contains backport patches that do not cover the entire JDK.

  2. predates the full open-sourcing, so is not identical to the old Oracle JDK.

So not only is the license for versions starting with 11 better than ever in Java’s history, the licensing situation for 8 is not that good. Java 8 is well past its free support period.

Licensing alone is a reason to update.

I try to make it more practical. Actually, in the case of the weeks to months' estimation, I often managed to migrate the application in a couple of days. It is often a matter of simply trying it, and if you are lucky, you manage to upgrade it quite easily. Depending on what dependencies you use, or what code bases you use, it might be a bigger challenge.

The usual discussion about Oracle Java licensing is the typical FUD regarding Java and Oracle. OpenJDK and Oracle Java are as different as Red Hat Fedora and Red Hat Enterprise Linux.

If you do not want to pay for Red Hat Enterprise Linux support, just go with Fedora, or any other Linux distribution.

It is exactly the same with Java distributions.

Should You Migrate Everytime?

Should we stick to using LTS versions, or should we use the latest versions of Java [1]? If you have the time available, I would recommend using the latest version of Java because you can use the new features and improvements. It always increases developer productivity and application reliability [2]. You have to do it every six months, because you cannot use the new minor versions.

If you do not have that time available to upgrade every six months, you might opt to using only the long term support versions. However, then, each time you need to upgrade your long term support version, that actually might take quite a bit more time as well. In the end, I think staying on long term support versions or using the latest version should not differ much in the investment in upgrading.

JDK 17 is a LTS version. You must anyway migrate to JDK 17. The only discussion point is when and certainly not if. Decide

You are a laggard organization

Start to plan your migration and allocate needed resources and budget to the migration. You should hope your competition will not release new features and beat you.

You are a modern organization

You are already migrating to JDk 17 and will complete it in the next months. The discussion is moot.

You are a DevOps organization

You have already completed migration. Congratulations, you can focus on business value and beat your competitors.

How Big is the Migration Effort?

When we start developing against the new Java version, it’s recommended to start with your local machine, get that up and running first. Then upgrade your build environment, so it supports the latest version of Java. Get everything built and tested over there. Then at the end, release it to the other environments, including the production environment.

When upgrading Java, you might upgrade from 8 to 17 at once. If you have encountered any issues, it might be hard to pinpoint what’s caused the exact issue.

Therefore, it might be better to do the migration, step by step. Maybe you migrate from 8 to 11 first, or maybe from 8 to 9. If you encounter any issues, you can easily see what’s changed in that Java version.

Answers can often be found through Google or StackOverflow. That way, it is easier to get the upgrades done instead of in one big bang.

However, even after years of experience, I cannot estimate how long an upgrade will take without having in-depth information about the project. A lot depends on how many dependencies your application has. Often, upgrading your dependencies to the latest version resolves many of the issues that would occur during a Java upgrade.

How do we move forward? Now we start by compiling the source code on the new Java version, we run it. If that succeeds, and we make the necessary fixes, we go to running the unit tests. If we fix that as well, we can package the application, and in the end, we can run the application. Based on the nice ingredients, we should get a nice result.

New Features

The official list of new features is

JEP 306 - Restore Always-Strict Floating-Point Semantics

Very useful if you are a mathematical library developer

JEP 356 - Enhanced Pseudo-Random Number Generators

Simpler usage of random generators in the API

JEP 382 - New macOS Rendering Pipeline

Support of Metal graphics API on macOS

JEP 391 - macOS/AArch64 Port

Support of Apple proprietary processors based on the ARM architecture

JEP 398 - Deprecate the Applet API for Removal

Applets are dead for years, now the associated API is deprecated and will be removed in the future

JEP 403 - Strongly Encapsulate JDK Internals

Stop using unsafe operations in your libraries. Use the JDK tools to identify suitable supported classes with the same functionality

JEP 406 - Pattern Matching for switch (Preview)

Pattern matching is the new kid on the block. We have now nice features for the switch expression.

JEP 407 - Remove RMI Activation
JEP 409 - Sealed Classes

Sealed class release completes the implementation of algebraic data types

JEP 410 - Remove the Experimental AOT and JIT Compiler

Nobody uses them.

JEP 411 - Deprecate the Security Manager for Removal
JEP 412 - Foreign Function & Memory API (Incubator)
JEP 414 - Vector API (Second Incubator)

Cool feature supporting SIMD hardware.

JEP 415 - Context-Specific Deserialization Filters

Increase security.

The new features you should use on a daily basis are described bellow. They will impact the appearance and legibility of your source code.

Algebraic Types

Records [1] are immutable classes. A record and all associated operations are defined in one statement.

public record Person(String lastname, String firstname, LocalDate birthday) {}

Sealed classes are a powerful constructs to constrain your inheritance hierarchy.

Pattern Matching for Switch

A preview of pattern matching for switch extends the language of patterns in Java. It allows switch expressions and statements to be tested against a number of patterns, each with a specific action. This enables complex data-oriented queries to be expressed concisely and safely.

Among the goals of this feature include expanding the expressiveness and application of switch expressions and statements by enabling patterns to appear for labels, relaxing the historical null-hostility of switch when desired, and introducing two kinds of patterns: guarded patterns, which allow pattern matching logic to be refined with arbitrary Boolean expressions, and parenthesized patterns, which resolve some parsing ambiguities.

In JDK 16 [2], the instanceof operator was extended to take a type pattern and perform pattern matching. The modest extension proposed allows the familiar instanceof-and-cast idiom to be simplified. The implementation of the boolean equals(Object o) method is reduced to one expression without any conditional statement. Try the new implementation in your code.

You should use Streams in all your code fragments. Stream concepts were introduced with Java 8.

The majority of your loops and conditional statements shall be replaced with stream pipelines and operations.

Your methods should not return null values. The specialized stream Optional<T> was added to provide a better approach.

1. Beware the Java architects announced with the release of Java 17 that LTS releases will be released every two years. Until now the release cycle was three years
2. Do not underestimate how more motivated developers are if they can use actual techniques and language features.