- Most of the JDKs mentioned are simply builds of openjdk. There are a few exceptions with alternative runtimes from e.g. IBM. But unless you have a good reaon to use those, use any OpenJDK build. They are functionally identical and the certified ones pass an extensive test suite to guarantee that. Coretto is a safe bet with long term support and backported fixes.
- There's a difference between developers and production usage here. Tools like sdk man are for developers that need to switch between specific versions in different projects. You see the same in the python, ruby, js, etc. world. System wide installations aren't that useful. Unlike many of those, project dependencies are never system wide. There's no global installation of Java dependencies.
- Avoid Oracle's builds unless you need them for compliance reasons. Their licensing can get expensive and they are famously pretty aggressive on enforcing terms. There is no functional advantage to using their builds. They aren't faster or better in any way. There is no Oracle specific secret sauce.
- If you are on Linux or mac, getting your sdk via your favorite package manager is fine for casual use. Just be aware that this might not necessarily work with all software projects you want to work on. If that matters to you, that's what sdkman is for.
- JDKs take up a lot of space. A lot of tools are trigger happy to add JDKs but don't necessarily remove them. Tracking down and removing redundant JDKs is something I have to do regularly. Some tools try to be a bit too smart and will ignore the presence of perfectly good jdks I have installed with sdkman (e.g. intellij).
- Use containers for deployment and pick the right base image. You should not need server side jdk installations unless you are doing things the old school way.
And don’t hesitate to use a JRE (Java Runtime Environment) if all you need is to run java/jvm applications - assuming the application doesn’t already ship with its own runtime. A JDK is roughly 140 MB, while a JRE is about 60 MB (and can be further minimized). I’ve seen installations of the full OpenJDK just to run apps, which is unnecessary in most cases.
I just don't see the point in installing a version manager specifically for the JDK. It's fine to have multiple installed, and at least on Debian-likes you have the built in update-java-alternatives method to switch between them.
On macOS I wrote my own 9-line Zsh function that lists the JDKs available and sets JAVA_HOME.
In containers you'll never switch at all, just install whatever you want and be done with it.
ETA: I see in another comment someone said this doesn't work for things that aren't OpenJDK. But I've yet to run into a situation where I'd want to install anything except OpenJDK. That said, I think update-java-alternatives would work with them if they provide deb files to install themselves.
The update-java-alternatives tool is suitable for adjusting the JDK for everything at once, but it lacks the ease of use of something like SDKMan when you have one project stuck at Java 8 and another on 11, and another on 17, or perhaps you're testing a branch on 24, etc.
Then it's just:
sdk use java 11.0.29-tem
And in that terminal it will use that, while another terminal happily uses a different version. That's useful when you are running two tools on different Java versions which interact. Installing another version is trivial too.
With Mill build tool that I'm working on, you don't need to install Java at all! (https://mill-build.org/blog/16-zero-setup.html). Instead, it gets bootstrapped automatically when you launch the `./mill` script like any other third-party dependency. You can use any version you want just by editing the config file and it'll be downloaded and cached on demand. You can also configure different JVM versions to use in different Java modules without worrying about conflicts between them.
You don't need to globally install Apache-Commons, nor is there a "Apache Commons Version Manager" that you need to first install to then manage your different versions of Apache Commons. So why should the JVM need such a thing? Well with Mill, it doesn't
pro tip: don't bother with SDKMAN. use https://mise.jdx.dev to install Java, it can also install a bunch of other languages and tools. it's most likely the last tool version manager you'll ever need.
I found the documentation confusing and as so often with general-approach tools too overwhelming for what I'm trying to do. sdkman works fine for what I need it for and usually you only need one instance of gradle and maven installed.
And sdkman is written in rust and only needs curl, zip and unzip, no JVM.
I use version managers for Python, Node, Ruby, and others. But for Java, none. I have all the recent versions of Java on my Linux and Windows devices. I download the zip and extract it to a common directory "Java". Setting the path within IDEs is easy, and is mostly unavoidable (regardless of a version manager). Running standalone programs is not that complicated too.
Yes, I have a dead-simple env.bat/env.sh file that sets up specific Java and Maven versions for programs that IDEs struggle with building. I don't see the need to set up an extra tool to install more Java versions, because I don't rebuild my dev environments from scratch every week. My Java 8 installation is three-years old now and has survived a complete Windows reinstallation.
Before even deciding which Java to install, you have to decide which _version managers_ to use:
1. No version manager, download and install manually. Not that hard, since it's just a zip file and maybe set JAVA_HOME envvar. If you need multiple versions to co-exist, skip this.
2. Use OS' "native" package manager. Brew, apt, chocolatey.
3. Generic package manager like asdf.
4. SDKMAN!, JBang, jEnv, jabba...
Deciding is easy. But remembering which one you used 6 months ago when you want to install another version...
I'd skip that and use mise. It's an asdf compatible manager and does so much more. It manages scripts (replacing make), environment variables and it's super fast.
> multiple vendors has always been a thing in Java since the early 2000's.
Early 2000s? There was usually one language version that circulated. We had the blackdown java on debian, whatever version sun hosted (1.3?) and something IBM made which was probably on a password protected ftp site available to corporate clients. And it was like that for years. Now there's like 10 vendors supporting 3-5 different major language versions that change every few months.
+1 sdkman! is awesome. I've been using sdkman! for a decade to manage Java installations. Doesn't seem to work on freebsd though, which I have to use freebsd's pkg instead.
On Windows, the only sane way to install Java seems to be scoop.sh or chocolatey
Fortunately, the Java ecosystem isn’t JS where breakage is so common that you have to be extra careful about the version of Node you’re using. As a Clojure programmer, I have never seen a case where it mattered which vendor my JVM was coming from, and 95% of the time I don’t care which version I’m using, as long as it’s reasonably recent.
For the remaining 5%, on macOS, my JVM version manager is this zsh one-liner:
> I have never seen a case where it mattered which vendor my JVM was coming from
As I understand it, Oracle's JVMs only get free updates for a limited time. If you keep using them after that you risk getting caught in a license audit.
Coming from Python, I get the feeling Java tooling is ripe for an astral-shaped astroid.
Am I just a Java rookie, or would Java benefit from equivalents for Python's ruff/uv/ty?
Obviously, lots of tooling already exists (Python's did too). But distilling all the lore and xml into a handful of fast opinionated cli tools seems useful to me anyway.
I remember manually choosing dependencies by pasting them from maven to pom.xml and jetbrains IDE kindly nudged me every day to keep up to date whenever newer versions were available. Version massaging took a large portion of the day because I was too autistic to ignore a yellow alert.
There's nothing like direnv + nix + a flake with the appropriate dev shell config...
And seriously, any LLM can write the .envrc, nix.conf, flake.nix files if it's too complicated.
Picking a JDK is simple. You pick the latest Temurin LTS. It'll work, and if it doesn't, grab the Zulu with JavaFX already plugged in or suss out the incantation for implanting it into your Temurin through web search.
Besides JDK management SDKMan also provides an easy to understand interface for toolchains for things like Clojure and Kotlin and also stuff such as Quarkus.
Couple of points here:
- Most of the JDKs mentioned are simply builds of openjdk. There are a few exceptions with alternative runtimes from e.g. IBM. But unless you have a good reaon to use those, use any OpenJDK build. They are functionally identical and the certified ones pass an extensive test suite to guarantee that. Coretto is a safe bet with long term support and backported fixes.
- There's a difference between developers and production usage here. Tools like sdk man are for developers that need to switch between specific versions in different projects. You see the same in the python, ruby, js, etc. world. System wide installations aren't that useful. Unlike many of those, project dependencies are never system wide. There's no global installation of Java dependencies.
- Avoid Oracle's builds unless you need them for compliance reasons. Their licensing can get expensive and they are famously pretty aggressive on enforcing terms. There is no functional advantage to using their builds. They aren't faster or better in any way. There is no Oracle specific secret sauce.
- If you are on Linux or mac, getting your sdk via your favorite package manager is fine for casual use. Just be aware that this might not necessarily work with all software projects you want to work on. If that matters to you, that's what sdkman is for.
- JDKs take up a lot of space. A lot of tools are trigger happy to add JDKs but don't necessarily remove them. Tracking down and removing redundant JDKs is something I have to do regularly. Some tools try to be a bit too smart and will ignore the presence of perfectly good jdks I have installed with sdkman (e.g. intellij).
- Use containers for deployment and pick the right base image. You should not need server side jdk installations unless you are doing things the old school way.
And don’t hesitate to use a JRE (Java Runtime Environment) if all you need is to run java/jvm applications - assuming the application doesn’t already ship with its own runtime. A JDK is roughly 140 MB, while a JRE is about 60 MB (and can be further minimized). I’ve seen installations of the full OpenJDK just to run apps, which is unnecessary in most cases.
I just don't see the point in installing a version manager specifically for the JDK. It's fine to have multiple installed, and at least on Debian-likes you have the built in update-java-alternatives method to switch between them.
On macOS I wrote my own 9-line Zsh function that lists the JDKs available and sets JAVA_HOME.
In containers you'll never switch at all, just install whatever you want and be done with it.
ETA: I see in another comment someone said this doesn't work for things that aren't OpenJDK. But I've yet to run into a situation where I'd want to install anything except OpenJDK. That said, I think update-java-alternatives would work with them if they provide deb files to install themselves.
The update-java-alternatives tool is suitable for adjusting the JDK for everything at once, but it lacks the ease of use of something like SDKMan when you have one project stuck at Java 8 and another on 11, and another on 17, or perhaps you're testing a branch on 24, etc.
Then it's just:
And in that terminal it will use that, while another terminal happily uses a different version. That's useful when you are running two tools on different Java versions which interact. Installing another version is trivial too.
You can also check in an .sdkmanrc into each respective project which defines the required Java version.
Then SDKMAN! will perform the switch automatically when you enter the directory.
https://sdkman.io/usage/#env-command
direnv is great for switching any envnvariables let given directory.
I use it when I have projects with different jdks or nodejs.
With Mill build tool that I'm working on, you don't need to install Java at all! (https://mill-build.org/blog/16-zero-setup.html). Instead, it gets bootstrapped automatically when you launch the `./mill` script like any other third-party dependency. You can use any version you want just by editing the config file and it'll be downloaded and cached on demand. You can also configure different JVM versions to use in different Java modules without worrying about conflicts between them.
You don't need to globally install Apache-Commons, nor is there a "Apache Commons Version Manager" that you need to first install to then manage your different versions of Apache Commons. So why should the JVM need such a thing? Well with Mill, it doesn't
pro tip: don't bother with SDKMAN. use https://mise.jdx.dev to install Java, it can also install a bunch of other languages and tools. it's most likely the last tool version manager you'll ever need.
I found the documentation confusing and as so often with general-approach tools too overwhelming for what I'm trying to do. sdkman works fine for what I need it for and usually you only need one instance of gradle and maven installed.
And sdkman is written in rust and only needs curl, zip and unzip, no JVM.
Ah, it was written in Groovy last time I looked at it I believe. In any case here’s how to install a default java:
`mise ls-remote java` to show all vendors and versions, or just `mise latest java@temurin` (or any other vendor) to get the latest version string
`mise use -g java@<version>` to install it and set it as a default
I use version managers for Python, Node, Ruby, and others. But for Java, none. I have all the recent versions of Java on my Linux and Windows devices. I download the zip and extract it to a common directory "Java". Setting the path within IDEs is easy, and is mostly unavoidable (regardless of a version manager). Running standalone programs is not that complicated too.
Yes, I have a dead-simple env.bat/env.sh file that sets up specific Java and Maven versions for programs that IDEs struggle with building. I don't see the need to set up an extra tool to install more Java versions, because I don't rebuild my dev environments from scratch every week. My Java 8 installation is three-years old now and has survived a complete Windows reinstallation.
Good luck when you sysadmin apply a decent automated security suite and removes the old Java 8 installation because isn't updated
1 reply →
Before even deciding which Java to install, you have to decide which _version managers_ to use:
1. No version manager, download and install manually. Not that hard, since it's just a zip file and maybe set JAVA_HOME envvar. If you need multiple versions to co-exist, skip this.
2. Use OS' "native" package manager. Brew, apt, chocolatey.
3. Generic package manager like asdf.
4. SDKMAN!, JBang, jEnv, jabba...
Deciding is easy. But remembering which one you used 6 months ago when you want to install another version...
I'd skip that and use mise. It's an asdf compatible manager and does so much more. It manages scripts (replacing make), environment variables and it's super fast.
I have a feeling somebody will link that xkcd post soon...
1 reply →
I don't get the point.
First of all, multiple vendors has always been a thing in Java since the early 2000's.
Second, configuring a couple of environment variables isn't that much of a challenge.
Third, all IDEs have an option to use a bundled JVM, and allow for JVM selection per project.
Finally, for applications the modern way is to build the runtime alongside the application, or AOT compilation.
> multiple vendors has always been a thing in Java since the early 2000's.
Early 2000s? There was usually one language version that circulated. We had the blackdown java on debian, whatever version sun hosted (1.3?) and something IBM made which was probably on a password protected ftp site available to corporate clients. And it was like that for years. Now there's like 10 vendors supporting 3-5 different major language versions that change every few months.
Yes, doesn't matter if it was commercial or not, or what operating systems.
We are not talking about what was available only to GNU/Linux folks as free beer.
+1 sdkman! is awesome. I've been using sdkman! for a decade to manage Java installations. Doesn't seem to work on freebsd though, which I have to use freebsd's pkg instead.
On Windows, the only sane way to install Java seems to be scoop.sh or chocolatey
From what I’ve seen is most organisations have moved to Amazon Corretto, and stuck with it.
It’s TCK-certified, supported by Amazon, and completely free.
So I don’t see the need to use any other distribution, unless it is for a niche requirement.
Fortunately, the Java ecosystem isn’t JS where breakage is so common that you have to be extra careful about the version of Node you’re using. As a Clojure programmer, I have never seen a case where it mattered which vendor my JVM was coming from, and 95% of the time I don’t care which version I’m using, as long as it’s reasonably recent.
For the remaining 5%, on macOS, my JVM version manager is this zsh one-liner:
> I have never seen a case where it mattered which vendor my JVM was coming from
As I understand it, Oracle's JVMs only get free updates for a limited time. If you keep using them after that you risk getting caught in a license audit.
Coming from Python, I get the feeling Java tooling is ripe for an astral-shaped astroid.
Am I just a Java rookie, or would Java benefit from equivalents for Python's ruff/uv/ty?
Obviously, lots of tooling already exists (Python's did too). But distilling all the lore and xml into a handful of fast opinionated cli tools seems useful to me anyway.
I remember manually choosing dependencies by pasting them from maven to pom.xml and jetbrains IDE kindly nudged me every day to keep up to date whenever newer versions were available. Version massaging took a large portion of the day because I was too autistic to ignore a yellow alert.
I would say as well as using SDKMan, you should use Jenv shell plugin to easily manage your JDK versions across projects.
https://github.com/jenv/jenv
All you have to do is link your SDKMan binaries with Jenv and you can easily switch with one command.
There's nothing like direnv + nix + a flake with the appropriate dev shell config... And seriously, any LLM can write the .envrc, nix.conf, flake.nix files if it's too complicated.
Ever since I found `asdf`, I threw away jenv, nvm, fmn and rvm.
Or just `apt install default-jdk-headless` and move on with your life
There's always Gradle Toolchains as well, which allows you to put the JDK configuration in the branch next to the source code.
Happy sdkman user for many years.
Never understood why you’d use sdkman for Java. I just do:
1. brew install openjdk@<version>
2. ln -s <homebrew path> </Library/JavaVirtualMachines/>
3. /libexec/java_home -v <version>
Afaik, with some aliases in you *shrc it basically reimplements sdkman, what else does it give you?
This works if all you need is OpenJDK. Per the article, sdkman allows one to install and switch between different versions and brands of JDKs.
12 replies →
The version manager approach feels like a giant step backward to me. Manage dependencies with containers.
That's a lot of words to promote SDKMan.
Picking a JDK is simple. You pick the latest Temurin LTS. It'll work, and if it doesn't, grab the Zulu with JavaFX already plugged in or suss out the incantation for implanting it into your Temurin through web search.
Besides JDK management SDKMan also provides an easy to understand interface for toolchains for things like Clojure and Kotlin and also stuff such as Quarkus.
[dead]