If you, like me, have to deal with multiple projects at different stages, like one being legacy, another one being the latest, and another one being a library or tool consumed by users also using different versions of Java, then you have a small Multiple JDK problem, assuming you only care for one vendor of JDK; otherwise, you have a Matrix JDK problem.

Courtesy of Karakun AG

Installing, managing, and switching between JDKs in your computer is no easy task these days where the majority of developers are still on Java 8, while a good chunk is now moving to Java 11. And there are many ways to do that.

This article is to help you through that process.

The Manual Way

You can go after your JDK vendor-of-choice website and download binaries, and install them all manually (or even better just extract them to some folder like $user/jdks and be done with it. But then you have to always verify and update JAVA_HOME to point to the one you really want for this and for that project.

Solutions for this would include using bash scripts, bash functions, and so on. The main problem? You may simply forget to call the script/function, and be hit with some UnsupportedClassVersionError to then only realize what's wrong.

I'll leave this to you to dig the internet for solutions, if you prefer the manual way. For advanced users, it may be the best choice. But I prefer some tooling for this. So, let's dive in:

The Better Way

In my opinion, the ideal way is by combining two open source tools that exist already for quite some time and you may already know at least one of them. What you don't know is that you can combine them.

Let's see how we get them to play ball together…

Install Multiple JDKs

Once you have SDKMAN! installed and configured, you will type:

$ sdk list java

Once you find the vendor and version you want to install, you will type:

$ sdk install java <id>

Let’s add four JDKs, two recent versions of Oracle OpenJDK and two LTS versions by AdoptOpenJDK.

Whenever asked by SDKMAN!, do not set any of them as the default.

AdoptOpenJDK build of OpenJDK 8u252 — LTS AdoptOpenJDK build of OpenJDK 11.0.7 — LTS Oracle OpenJDK 14 — Latest GA Oracle OpenJDK 15 — Early Access Builds of next release

These four versions should cover you well for legacy projects still stick to Java 8, but also put you in a nice place for modern projects with Java 11 as well as the possibility to experiment new features and enhancements on Java 14 and Java 15.

Alright, you’ve got 4 JDKs installed locally with SDKMAN! —I think this tool is really great for this use case, and I hope you enjoyed it too.

All JDKs installed can be found inside the following directory:

$ cd /Users/bruno/.sdkman/candidates/java $ ls

11.0.7.hs-adpt 14.0.1-open 15.ea.20-open 8.0.252.hs-adpt

Now, if you do want to just use one JDK at all times and not have to switch back and forth, you can use SDKMAN! to set your JDK of choice:

$ sdk current java

Using java version 15.ea.19-open $ sdk default java 15.ea.20-open

Default java version set to 15.ea.20-open

You can stop here and just use SDKMAN! but you will eventually forget to switch back based on the project you are working on, just like by using some manual shell script. And because of this, I prefer to auto-switch.

Manage Multiple JDKs with jEnv

While SDKMAN! can install and manage JDKs, the tool doesn't do a great job at auto-switching between versions for you automatically as you move from project A to project B.

For that, you will want jEnv.

Once you have it installed and configured, and multiple JDKs, whether with SDKMAN! or some other way, you will need to add those JDKs to jEnv. Here’s how:

$ cd ~/.sdkman/candidates/java $ ls -1

11.0.7.hs-adpt

14.0.1-open

15.ea.20-open

8.0.252.hs-adpt $ jenv add 15.ea.20-open

openjdk64-15-ea added

15-ea added

15-ea added ... $ jenv versions

system

1.8

1.8.0.252

11.0

11.0.7

14.0

14.0.1

* 15-ea (set by /Users/bruno/.jenv/version)

openjdk64-1.8.0.252

openjdk64-11.0.7

openjdk64-14.0.1

openjdk64-15-ea

Repeat the command jenv add for all other 3 versions.

jEnv has excellent features especially for those constantly using terminals. It will allow you to:

Set a Java version for your overall system. Set a Java version for the current directory/project you are in. Set a Java version for the current shell.

jEnv uses shim binaries and also manipulates the JAVA_HOME environment variable for you automatically. So, once you have these settings, jEnv will switch to whatever version makes most sense, based on the priority above and based on where you are. Neat! It has other nice features, so check the website for more documentation.

Auto-Switch Between Multiple JDKs

Now you have Java 8, 11, 14 and 15-EA available. So how do you switch back and forth? Let's set versions and switch back and forth.

First you set a Java version to be global default. I like to use an Early Access as my system default. Whenever I hit a new project, I will automatically attempt to work with an upcoming release, and this could help me identify potential problems I can then report back to the OpenJDK project. But you do you…

$ jenv global 15

With this setting, whenever you hit any folder on your terminal and you type java -version you will get OpenJDK 15 EA.

If you do have a project that must use Java 8, then you navigate to that project folder, and you type:

$ jenv local 1.8

This will create a file called .java-version with the following content:

$ cat .java-version

───────┬────────────────────────────────────────────────────────────

│ File: .java-version

───────┼────────────────────────────────────────────────────────────

1 │ 11.0

───────┴────────────────────────────────────────────────────────────

This file is what tells jEnv which JDK to use for when the terminal is on this folder.

Finally, if you are on some location and you want to temporarily switch to a specific JDK version, then you use jenv shell.

Here's a demonstration that can explain better all these concepts and how the Auto-Switch works:

I hope you enjoyed the read, and if you have questions, just reach out to me on Twitter.