Install JDK
This lesson installs a Java Development Kit on Windows, macOS, and Linux, then configures the PATH and JAVA_HOME environment variables that tools use to find it. The examples use Eclipse Temurin, but the steps are the same for any OpenJDK distribution. Replace the version number (25 below) with the current LTS you want.
Windows
Option 1: Installer (.msi)
- Go to adoptium.net, choose the latest LTS, Windows, x64 (or aarch64 on ARM devices), and download the
.msifile. - Run the installer. On the Custom Setup screen, enable:
- Add to PATH
- Set JAVA_HOME variable
- Finish the installation.
- Open a new terminal window. Terminals that were already open keep the old environment variables and will not see the change.
Option 2: winget
Windows 10 and 11 include the winget package manager. In PowerShell or Command Prompt:
winget search Temurin
winget install EclipseAdoptium.Temurin.25.JDK
winget search lists the available package IDs; use the ID that matches the version you want. Open a new terminal afterward.
Verify
java -version
javac -version
echo %JAVA_HOME%
In PowerShell, use echo $env:JAVA_HOME for the last line.
macOS
Option 1: Installer (.pkg)
- Download the macOS
.pkgfrom adoptium.net. Choose aarch64 for Apple Silicon (M-series) Macs and x64 for Intel Macs. Check under Apple menu → About This Mac if unsure. - Run the installer. The JDK is placed in
/Library/Java/JavaVirtualMachines/.
macOS ships a /usr/bin/java stub that automatically uses the newest JDK in that folder, so java and javac work in a new terminal without editing PATH.
Option 2: Homebrew
brew install --cask temurin
This installs the latest Temurin release. Specific versions are available as separate casks, for example brew install --cask temurin@21.
Setting JAVA_HOME on macOS
Many build tools expect JAVA_HOME. macOS provides a helper that prints the path of an installed JDK:
/usr/libexec/java_home # newest installed JDK
/usr/libexec/java_home -v 21 # a specific version
/usr/libexec/java_home -V # list all installed JDKs
Add this line to ~/.zshrc (zsh is the default shell on current macOS):
export JAVA_HOME=$(/usr/libexec/java_home)
Then reload the configuration and verify:
source ~/.zshrc
echo $JAVA_HOME
java -version
Linux
Debian and Ubuntu (apt)
sudo apt update
apt search openjdk | grep jdk # see which versions your release offers
sudo apt install openjdk-21-jdk # substitute the version listed
Install the package ending in -jdk, not -jre. The -jdk-headless variant omits GUI libraries and suits servers.
Distribution repositories may not carry the newest release. For the latest Temurin on Debian/Ubuntu, Adoptium publishes its own apt repository; follow the instructions at adoptium.net/installation.
Fedora, RHEL, Rocky Linux (dnf)
dnf search openjdk
sudo dnf install java-21-openjdk-devel
On Red Hat–based systems, the -devel package contains javac; the package without -devel contains only the runtime.
Arch Linux
sudo pacman -S jdk-openjdk
Switching between installed versions
Debian/Ubuntu and Fedora use the alternatives system to choose which installed JDK the java command runs:
sudo update-alternatives --config java # Debian/Ubuntu
sudo alternatives --config java # Fedora/RHEL
Choose the number of the version you want. Repeat for javac to keep them matched.
Setting JAVA_HOME on Linux
Find where the JDK is installed:
readlink -f "$(which javac)"
# /usr/lib/jvm/java-21-openjdk-amd64/bin/javac
JAVA_HOME is the directory above bin. Add to ~/.bashrc (or ~/.zshrc):
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
export PATH="$JAVA_HOME/bin:$PATH"
Reload with source ~/.bashrc.
SDKMAN! (macOS, Linux, WSL)
SDKMAN! installs and switches between many JDK versions and vendors without administrator rights. It is popular with developers who work on several projects.
curl -s "https://get.sdkman.io" | bash
# open a new terminal, then:
sdk list java # shows available versions and vendor identifiers
sdk install java <identifier> # e.g. an identifier ending in -tem for Temurin
sdk use java <identifier> # use a version in the current terminal only
sdk default java <identifier> # make it the default for new terminals
Identifiers combine a version and a vendor code, such as -tem for Temurin. Copy one exactly from the sdk list java output. SDKMAN! sets JAVA_HOME and PATH automatically.
Manual Archive Installation (Any OS)
When you cannot use an installer or lack administrator rights:
- Download the
.zip(Windows) or.tar.gz(macOS/Linux) from the vendor. - Extract it to a folder you control, such as
C:\dev\jdk-25or~/jdks/jdk-25. - Set
JAVA_HOMEto that folder and addJAVA_HOME/binto thePATHas shown below.
Nothing else is required. A JDK is self-contained, and removing it is simply deleting the folder.
PATH and JAVA_HOME Explained
| Variable | Points to | Used by |
|---|---|---|
PATH | The JDK's bin directory (among many others) | Your shell, to find java, javac, jshell when you type them |
JAVA_HOME | The JDK's root directory (the one containing bin) | Maven, Gradle, Tomcat, IDEs, and scripts that need to locate the JDK |
JAVA_HOME must point to the JDK root, not to bin. A common error is setting it to .../jdk-25/bin, which makes tools look for .../jdk-25/bin/bin/java and fail.
Setting them manually on Windows
- Open the Start menu, search Edit the system environment variables, and open it.
- Click Environment Variables.
- Under User variables (or System variables for all users), click New:
- Name:
JAVA_HOME - Value:
C:\Program Files\Eclipse Adoptium\jdk-25.0.1.8-hotspot(your actual folder)
- Name:
- Select the
Pathvariable, click Edit, click New, and add%JAVA_HOME%\bin. Move it above any older Java entries. - Click OK on every dialog, then open a new terminal.
Referencing %JAVA_HOME%\bin in Path, rather than repeating the full folder, means only JAVA_HOME needs changing when you upgrade.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
'java' is not recognized / command not found | JDK bin not on PATH, or terminal opened before installation | Open a new terminal; check PATH |
java -version shows an old version | An older Java appears earlier on PATH | Move the new JDK's bin higher; on Linux use update-alternatives |
javac not found but java works | Only a runtime installed, or wrong package (-jre) | Install the full JDK (-jdk / -devel) |
java and javac report different versions | PATH mixes two installations | Ensure both come from the same bin directory |
Maven/Gradle: JAVA_HOME is not defined correctly | JAVA_HOME unset, or pointing at bin | Set it to the JDK root |
UnsupportedClassVersionError when running | Class compiled with a newer JDK than the one running it | Run with the newer JDK, or compile with --release <older version> |
The last error deserves explanation. Each Java version writes a version number into the .class files it produces. A JVM refuses to load classes from a newer version than itself, because they may use bytecode features it does not understand. javac --release 17 App.java compiles code that can run on Java 17 and later, even when using a newer JDK, and also checks that the code uses only APIs available in Java 17.
Final Check
java -version
javac -version
jshell --version
All three should report the same version. Then start JShell and evaluate an expression:
$ jshell
| Welcome to JShell -- Version 25.0.1
| For an introduction type: /help intro
jshell> 2 + 3 * 4
$1 ==> 14
jshell> /exit
| Goodbye
If these commands work, the JDK is correctly installed and ready for the rest of the tutorial.