Introduction
Keeping your JDK current is not just important – it is the smart thing to do. By staying current you can benefit from the latest security and performance enhancements. This means that even if your code stays the same, your users’ security and their experience of the application can improve over time. We therefore strongly recommend that all Java users remain on actively supported versions and apply Critical Patch Update security patches without delay.
There are two paths for staying current: you can apply updates of the same Java version (updating), or you can adopt newer Java versions (upgrading). This blog post will guide you in thinking about when to update and when to upgrade.
Before we dig in, it is important to clarify some terms we will use in this post. A Feature Release is a release where the specification of Java SE can be changed: APIs, tools, and other functionality can be added, deprecated, or removed. Feature releases are referred to generally by their number: JDK 21, JDK 17, JDK 8, and so on. Oracle offers Long Term Support for specific feature releases, such as Oracle JDK 21. An Update Release is an update made to a feature release, such as JDK 21.0.3, JDK 17.0.11 and JDK 8u411.
Updating versus Upgrading
Updating is, for the most part, a simple exercise: the risk of incompatibilities is small, there are clear benefits for the stability and security of your systems, and there are occasionally fixes that can improve performance. Sometimes you must update to manage changes in your firmware or operating system, to gain new cryptographic algorithms and disable potentially-insecure ones, and to use new hardware.
Upgrading (from JDK 21 to JDK 22, for example) has a potentially higher cost than “updating”, but correspondingly higher benefits: developers get new language features, new tools, and new APIs, which make it easier to code and maintain existing applications. For existing applications, even if the code is not changed or the application is not re-compiled, new JDK Feature Releases can offer larger performance improvements. Newer JDK versions, depending on your workload, typically start faster (start up), reach peak performance sooner (warmup), run faster (throughput), and use available resources better. They can introduce better tools for monitoring and debugging, and enable newer, specialized deployment models. The flip side of this is that Feature Releases might also remove or deprecate old APIs, retire older tools, stop supporting older operating systems and architectures, and require updates to third-party tools, libraries, and toolchains. To avoid these costs and risks, some developers and administrators choose to remain on a single release for a long time. For example, Oracle JDK 8 was released in 2014 and will be supported by Oracle until at least December 2030. However, all versions reach end-of-life eventually, so while you can postpone upgrading, you still need to plan for it accordingly.
At first glance, it would appear as if users need to satisfy two competing goals to maximize the benefits of using Java. Existing applications should work for as long as possible with as few changes as possible (besides updating the JDK to current Update Releases). On the other hand, developers work better when they have access to the new language features, APIs, and development practices that come with new Feature Releases. How long should we ask developers to use older coding practices that are increasingly at odds with general practices and existing sample code? How large or small of a performance boost, and in what areas, would warrant the cost of adopting a newer version? What is the best way to balance these goals?
In reality, once you free yourself from the self-imposed requirement of using a single Java version everywhere, you can get the best of both worlds by using the following guidelines to decide when to stay on the Oracle JDK Feature Release you are already using, and when to upgrade to a new one.
Use Multiple Runtimes
You don’t have to mandate a single JDK feature release for all Java applications. In the past, when there was only one major version of Java every few years, and most hard drives were measured in megabytes, it was unusual for each Java application to have its own Java runtime. Rather, it was common for all applications in a server to share a single Java runtime, and switching the Java runtime for one application meant changing it for all applications. To ensure that upgrading one application didn´t force others to upgrade prematurely, organizations usually choose to standardize on a specific Java version for every application. Organizations that wanted to upgrade to a new runtime had “flag days” on which ALL the applications – both in production and in development – had to upgrade to the same new runtime at the same time.
These all-or-none upgrade policies no longer make sense. Modern servers have more memory and storage than before. Containers now offer a way to share hardware without sacrificing the isolation of systems; it is now common to containerize applications so that each one can have its own Java runtime. Tools like jlink and java packager make it easier for application developers to bundle a Java runtime with their application. There is no longer a need to use a single Java feature release for all use cases; every application can have its own runtime and therefore move at its own pace. It is important to make sure all your runtimes are up to date with the latest update releases, and to not use any end-of-life (EOL) versions so that you benefit from security and performance enhancements.
Application-Specific Guidelines
Deciding which JDK version to run an application on will depend on where the application is in its lifecycle.
If developers are actively working on an application, asking them to upgrade to a newer Feature Release is reasonable. Once the application is no longer in active development, developers shouldn’t be asked to update to a new feature release without a good reason, such as costs savings through better application performance or, for long-lived applications, the approaching end-of support of the release they use. Non-trivial, stable applications in production should use an LTS release.
For new, complex projects that won’t be put into production for at least a year, aim to use the latest JDK feature version, even if is not LTS. Your code might not even be final before the next LTS is here; by starting in the latest release and adopting the next LTS early you maximize the amount of time your code can run on a stable LTS release. As usual, you need to take care that any third-party tools and libraires that you wish to use are supported with the JDK version you plan to use.
For new code meant to be released within a year, use the latest LTS release that has been available for at least nine months, or a newer feature release. The reason to use an LTS that has been available for at least nine months is that your application may have dependencies on third-party components, and the nine months wait time gives those third parties time to confirm that the components fully support the LTS version. If an LTS release has been available for more than nine months and a dependency has not yet been updated to support it, consider replacing your dependency with an alternative that is more actively maintained.
If your application is being actively updated, with new features being tested and added, consider migrating it to a new LTS within two years of that LTS being released. If your developers are still working on an application, they can test and can address migration requirements as a part of the overall maintenance of the application. Making sure that your application is on the most recent LTS before it stops being actively updated and it reaches the “just keep it running as-is with no changes” state will, again, maximize the amount of time you can rely on an LTS before it reaches end of support.
If your application is running but not actively being changed, stay on the Feature Release you are already on, unless:
- that JDK version has less than one year left in its lifetime, or
- the application relies on tools and/or third-party libraries reaching end of support before the JDK version itself, or
- the application is using too much memory or CPU
Upgrading a “stable” application should be an option to be considered when the circumstances warrant it. You can get performance benefits by upgrading, extend the supported lifetime of your application, or you could take advantage of the tremendous stability of Java and use the resources that were going to perform the upgrade to develop new applications.
Conclusion
By keeping your JDK up to date and by following the guidelines presented here, you can maximize all of Java’s benefits: stability, security, and constant improvements in start up, warmup, throughput, and resource use. If you are a Java SE Subscriber or running in Oracle Cloud Infrastructure and would like hands-on assistance with updating or upgrading your Java Runtime, you can file a service request on My Oracle Support.
