With a new version of Java released every 6 months, and Java 17 just out, this has become a much more challenging decision.
If you are just writing Java for your own interest or in-house (with total control of the systems Java is running on) this is not a problem. You can choose to go with the latest version and enjoy all the benefits of the latest Java release.
If you have a commercial or open-source library that others use, the choice is much more nuanced. You have to balance being able to make use of newer features to improve your product and making sure that your users can still use the software in their products which may be using an older version of Java. We also want to avoid creating multiple versions of the codebase if at all possible.
Our strategy has always been to compile to an older version of Java but also to test the code against any new release to ensure compatibility. We avoid new JDK features which would break this backwards compatibility.
While there is a Java release every 6 months, not all releases are created equal. Only the LTS releases (8, 11 and 17) are supported after 6 months. So they are the ones worth considering as a long term compatibility level. Here is the current status of Java releases.
We review the version of Java we use once a year and have a clear statement for all our users where we give at least 12 months notice if we plan to change our compatibility level. This is important to help them with their planning.
So far we have chosen to support Java 8 as our minimum level of Java needed. Most of our customers are still on Java 8 (although Java 11 is increasing in uptake) so this is an easy call for us. We will be using Java 8 until at least 2023.
However, a nice feature of Java is that we can add features for later versions of Java and do lots of preliminary work for updating the codebase without breaking this compatibility. Java 8 allows code for Java 8 and another Java release in a multi-jar which will run under Java 8 but support later JDKs. For example, Java 9 added the very powerful module feature, which we can support without breaking Java 8 support. So it is possible to add these features in now. You can also create 2 versions or any class (one for Java 8 and one for later versions). You just cannot use Java language features later than Java 8 in Java 8 code.
So our code will run on Java 8, Java 11, Java 17 and whatever the latest release is, with some extra features. Hopefully that is the optimum tradeoff between backwards compatibility and keeping up with new features.
If you have any ideaa on which version we should support please add your comments below.