Installation #
Java runs on the JVM (Java Virtual Machine), which means you need to install the JDK (Java Development Kit) — not just the JRE (Java Runtime Environment) — to compile and run programs. Installing Java is a bit more involved than with other languages because there are several JDK distributions from different vendors, and you need to set up the JAVA_HOME environment variable so tools like Maven, Gradle, and IDEs can locate the JDK correctly. This article walks you through installing Java 21 (the latest LTS) on Windows, macOS, Ubuntu, and Fedora, and explains how to manage multiple Java versions on one machine using SDKMAN.
Choosing a JDK Distribution #
Before installing, it’s important to understand that Java isn’t a single product from a single vendor. Many JDK distributions exist, all compatible because they follow the same specification, but they differ in licensing, support, and optimizations:
| Distribution | Vendor | License | Notes |
|---|---|---|---|
| Oracle JDK | Oracle | Paid* | License required for production |
| OpenJDK | Oracle / community | GPL v2 | Reference implementation, free |
| Eclipse Temurin | Adoptium (Eclipse) | GPL v2 | Recommended for general use |
| Amazon Corretto | Amazon | GPL v2 | Optimized for AWS |
| Microsoft Build | Microsoft | GPL v2 | Optimized for Azure |
| Azul Zulu | Azul Systems | GPL v2 | Commercial support available |
| GraalVM | Oracle | GPL v2 | Native image compilation |
For learning and general development, use Eclipse Temurin from Adoptium — a community-managed OpenJDK distribution that’s free and available on every platform. If you work in a specific cloud environment (AWS, Azure), consider the vendor-optimized distribution.
For versions, always pick an LTS (Long-Term Support) release for serious projects. The current LTS versions are Java 21 (released September 2023, supported until 2028) and Java 17 (still widely used). Avoid non-LTS releases (22, 23, etc.) for production since they only get six months of support.
timeline
title Java LTS Releases and Support
2018 : Java 11 LTS
: Supported until 2026
2021 : Java 17 LTS
: Supported until 2029
2023 : Java 21 LTS
: Supported until 2028
2025 : Java 25 LTS
: PlannedInstalling on Windows #
Using the Official Installer (Eclipse Temurin) #
The easiest way on Windows is to use the .msi installer from Adoptium:
1. Go to https://adoptium.net/
2. Choose "Eclipse Temurin 21 (LTS)"
3. Download the .msi installer for Windows x64
4. Run the installer — check the options:
✓ "Add to PATH"
✓ "Set JAVA_HOME variable"
This saves you from manual configuration.
5. Click Next → Install → Finish
Using winget (Windows Package Manager) #
If you prefer the command line:
# Install Eclipse Temurin 21
winget install EclipseAdoptium.Temurin.21.JDK
# Or version 17 if needed
winget install EclipseAdoptium.Temurin.17.JDK
Setting JAVA_HOME Manually #
If the installer didn’t set it automatically, or you installed the JDK from another source:
# Open System Properties via PowerShell (as Administrator)
# Or: Control Panel → System → Advanced System Settings → Environment Variables
# Add JAVA_HOME (adjust the path to match your installation location)
[System.Environment]::SetEnvironmentVariable(
"JAVA_HOME",
"C:\Program Files\Eclipse Adoptium\jdk-21.0.3.9-hotspot",
"Machine"
)
# Add %JAVA_HOME%\bin to PATH
$currentPath = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
[System.Environment]::SetEnvironmentVariable(
"Path",
"$currentPath;%JAVA_HOME%\bin",
"Machine"
)
After that, close and reopen PowerShell or Command Prompt so the environment variable changes take effect.
Verification #
java -version
javac -version
echo %JAVA_HOME%
Expected output:
openjdk version "21.0.3" 2024-04-16 LTS
OpenJDK Runtime Environment Temurin-21.0.3+9 (build 21.0.3+9-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.3+9 (build 21.0.3+9-LTS, mixed mode, sharing)
javac 21.0.3
C:\Program Files\Eclipse Adoptium\jdk-21.0.3.9-hotspot
Installing on macOS #
Using Homebrew (Recommended) #
Homebrew is the most practical way to manage JDKs on macOS:
# Install Homebrew if you don't have it yet
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install Eclipse Temurin 21
brew install --cask temurin@21
# Or version 17
brew install --cask temurin@17
Setting JAVA_HOME on macOS #
macOS provides the /usr/libexec/java_home helper, which returns the JDK path dynamically. Add it to your shell config:
# For Zsh (default on macOS Catalina and later) — edit ~/.zshrc
echo 'export JAVA_HOME=$(/usr/libexec/java_home -v 21)' >> ~/.zshrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.zshrc
source ~/.zshrc
# For Bash — edit ~/.bash_profile
echo 'export JAVA_HOME=$(/usr/libexec/java_home -v 21)' >> ~/.bash_profile
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bash_profile
source ~/.bash_profile
The advantage of using /usr/libexec/java_home -v 21 over a hardcoded path: if the JDK patch version is updated (say from 21.0.2 to 21.0.3), you don’t need to change your configuration.
Verification #
java -version
javac -version
echo $JAVA_HOME
Listing All Installed JDKs on macOS #
/usr/libexec/java_home -V
# Example output:
# Matching Java Virtual Machines (2):
# 21.0.3 (x86_64) "Eclipse Adoptium" - "OpenJDK 21.0.3" /Library/Java/JavaVirtualMachines/temurin-21.jdk/...
# 17.0.11 (x86_64) "Eclipse Adoptium" - "OpenJDK 17.0.11" /Library/Java/JavaVirtualMachines/temurin-17.jdk/...
Installing on Ubuntu / Debian #
Using apt (OpenJDK from Ubuntu’s Repository) #
The easiest way on Ubuntu is via apt — it’s available in the official repository:
# Update package list
sudo apt update
# Install OpenJDK 21
sudo apt install openjdk-21-jdk -y
# Verify
java -version
javac -version
Using the Adoptium Repository (Eclipse Temurin) #
If you want the Temurin distribution specifically:
# Install dependencies
sudo apt install -y wget apt-transport-https gpg
# Add the Adoptium GPG key
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public \
| gpg --dearmor \
| sudo tee /etc/apt/trusted.gpg.d/adoptium.gpg > /dev/null
# Add the repository
echo "deb https://packages.adoptium.net/artifactory/deb \
$(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" \
| sudo tee /etc/apt/sources.list.d/adoptium.list
# Update and install
sudo apt update
sudo apt install temurin-21-jdk -y
Setting JAVA_HOME on Ubuntu #
# Find the installed JDK path
update-java-alternatives --list
# Example output:
# java-1.21.0-openjdk-amd64 2111 /usr/lib/jvm/java-1.21.0-openjdk-amd64
# Add to ~/.bashrc or ~/.zshrc
echo 'export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64' >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
Managing Multiple Versions with update-alternatives #
Ubuntu provides update-alternatives to switch between Java versions without changing environment variables:
# Register the JDK with alternatives (if not already automatic)
sudo update-alternatives --install /usr/bin/java java \
/usr/lib/jvm/java-21-openjdk-amd64/bin/java 2111
sudo update-alternatives --install /usr/bin/javac javac \
/usr/lib/jvm/java-21-openjdk-amd64/bin/javac 2111
# Pick the active version interactively
sudo update-alternatives --config java
Installing on Fedora / RHEL / CentOS #
Using dnf #
# Install OpenJDK 21
sudo dnf install java-21-openjdk-devel -y
# Verify
java -version
javac -version
Setting JAVA_HOME on Fedora #
# Find the JDK path
alternatives --list | grep java
# or
dirname $(dirname $(readlink -f $(which java)))
# Add to ~/.bashrc
echo 'export JAVA_HOME=/usr/lib/jvm/java-21-openjdk' >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
Managing Multiple Versions with alternatives #
# List all installed versions
alternatives --list | grep java
# Switch the active version
sudo alternatives --config java
sudo alternatives --config javac
Managing Multiple Versions with SDKMAN #
If you often switch between projects that use different Java versions — say one project uses Java 17 and another Java 21 — SDKMAN is the most elegant solution. SDKMAN works on macOS, Linux, and Windows (via WSL).
Installing SDKMAN #
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
# Verify
sdk version
Using SDKMAN #
# List all available Java distributions
sdk list java
# Install Eclipse Temurin 21
sdk install java 21.0.3-tem
# Install Temurin 17 (without changing the active version)
sdk install java 17.0.11-tem
# List installed versions
sdk list java | grep installed
# Switch the active version permanently
sdk use java 21.0.3-tem
# Switch the active version only for this terminal session
sdk use java 17.0.11-tem
# Set the default version
sdk default java 21.0.3-tem
SDKMAN per Project with .sdkmanrc #
SDKMAN supports a .sdkmanrc file at the project root to lock the Java version automatically:
# At the project root directory
echo "java=21.0.3-tem" > .sdkmanrc
# Enable auto-switching (add to ~/.bashrc or ~/.zshrc)
echo 'export SDKMAN_AUTO_USE=true' >> ~/.bashrc
source ~/.bashrc
# Now entering a project directory switches the Java version automatically
cd ~/projects/my-java21-project # automatically switches to Java 21
cd ~/projects/my-java17-project # automatically switches to Java 17
flowchart TD
A["cd into project directory"] --> B{Is there a .sdkmanrc?}
B -- Yes --> C["Read the Java version\nfrom .sdkmanrc"]
B -- No --> D["Use the default version\nfrom sdk default"]
C --> E{"Version already\ninstalled?"}
E -- No --> F["sdk install java that-version"]
E -- Yes --> G["sdk use java that-version"]
F --> G
D --> H["Java active"]
G --> H
style H color:#fff,stroke:#16a34a,stroke-width:2pxUnderstanding the JDK Structure #
Knowing what’s inside the JDK directory helps you understand why JAVA_HOME and PATH need to be configured:
$JAVA_HOME/
├── bin/
│ ├── java ← runs programs (.class / .jar)
│ ├── javac ← Java compiler → bytecode
│ ├── javadoc ← documentation generator from comments
│ ├── jar ← creates/opens .jar files
│ ├── jshell ← interactive REPL (since Java 9)
│ └── jps, jmap, jstack, jconsole ← JVM monitoring tools
├── lib/
│ └── src.zip ← standard library source code
├── include/ ← C headers for JNI
└── release ← build version information
Adding $JAVA_HOME/bin to your PATH lets you call all these tools from anywhere in the terminal.
Verifying a Complete Installation #
After installing, run all of these commands to make sure everything is correct:
# Java runtime version
java -version
# Compiler version
javac -version
# JAVA_HOME path
echo $JAVA_HOME # Linux/macOS
echo %JAVA_HOME% # Windows
# Test compiling and running a simple program
cat > Hello.java << 'EOF'
public class Hello {
public static void main(String[] args) {
System.out.println("Java " + Runtime.version() + " installed successfully!");
}
}
EOF
javac Hello.java # compile → produces Hello.class
java Hello # run
# Clean up
rm Hello.java Hello.class
Expected output:
Java 21.0.3+9-LTS installed successfully!
Ifjava -versionworks butjavac -versiongives a “command not found” error, you installed the JRE (runtime only) instead of the JDK (development kit). The JRE doesn’t include thejavaccompiler. Make sure you install a package whose name containsjdkordevel, not justjre.
Summary #
- Choose Eclipse Temurin — the OpenJDK distribution from Adoptium is the safest choice for general development: free, actively maintained, and available on every platform.
- Use an LTS version — Java 21 is the latest LTS; avoid non-LTS releases for serious projects because they’re only supported for six months.
JAVA_HOMEmust be set — many tools (Maven, Gradle, IDEs) depend on this variable to find the JDK; an installation withoutJAVA_HOMEoften causes confusing errors.- SDKMAN for multiple versions — if you work across many projects with different Java versions, SDKMAN with a per-project
.sdkmanrcis far more ergonomic than changingJAVA_HOMEmanually.- JDK isn’t JRE — make sure you install the JDK (which includes
javac), not just the JRE; withoutjavacyou can’t compile Java programs.- Verify with a real compilation — don’t just check
java -version; create and run a simpleHello.javaprogram to confirm the whole toolchain works.
Next: Core Syntax →