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:

DistributionVendorLicenseNotes
Oracle JDKOraclePaid*License required for production
OpenJDKOracle / communityGPL v2Reference implementation, free
Eclipse TemurinAdoptium (Eclipse)GPL v2Recommended for general use
Amazon CorrettoAmazonGPL v2Optimized for AWS
Microsoft BuildMicrosoftGPL v2Optimized for Azure
Azul ZuluAzul SystemsGPL v2Commercial support available
GraalVMOracleGPL v2Native 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
         : Planned

Installing 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 #

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:2px

Understanding 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!
If java -version works but javac -version gives a “command not found” error, you installed the JRE (runtime only) instead of the JDK (development kit). The JRE doesn’t include the javac compiler. Make sure you install a package whose name contains jdk or devel, not just jre.

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_HOME must be set — many tools (Maven, Gradle, IDEs) depend on this variable to find the JDK; an installation without JAVA_HOME often causes confusing errors.
  • SDKMAN for multiple versions — if you work across many projects with different Java versions, SDKMAN with a per-project .sdkmanrc is far more ergonomic than changing JAVA_HOME manually.
  • JDK isn’t JRE — make sure you install the JDK (which includes javac), not just the JRE; without javac you can’t compile Java programs.
  • Verify with a real compilation — don’t just check java -version; create and run a simple Hello.java program to confirm the whole toolchain works.

Next: Core Syntax →
About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact