Installing Java takes one command per platform. Setting it up well takes four decisions: the JDK version, the vendor build, how you switch versions, and which build tool and IDE read JAVA_HOME. This guide covers each decision and gives you a verified working setup for Windows, macOS, and Linux.
Quick Takeaways
- Pick JDK 25 (LTS) for new projects. Oracle lists Java 25 as an LTS release from September 2025, with premier support until September 2030.
- Use SDKMAN (
sdk install java) on macOS, Linux, and WSL to install, pin, and switch JDKs per project. - Let the build tool pin the Java version. Use
maven.compiler.releasein Maven and toolchains in Gradle, so teammates and CI compile with the same JDK. - Set
JAVA_HOMEonce. IDEs, Maven, and Gradle all resolve the JDK from it.
| Component | Recommended choice | Why |
|---|---|---|
| JDK | Temurin 25 (LTS) | Free, vendor-neutral, long support window |
| Version manager | SDKMAN (macOS/Linux/WSL) | Per-project JDKs via .sdkmanrc |
| Build tool | Maven or Gradle 9.x | Both handle Java 25 |
| IDE | IntelliJ IDEA or VS Code | Day-one support for new Java releases |
Which JDK Version Should You Install?
Java ships a feature release every six months. Only some releases are LTS (long-term support). Production systems should sit on an LTS line.
Java 8, 11, 17, 21, and 25 are LTS releases, and Oracle plans the next LTS, Java 29, for September 2027. Java 27 shipped on September 15, 2026, and its first update, 27.0.1, arrived October 20, 2026. Java 27 is a non-LTS release. Use it to try new features, not to anchor a long-lived service.
Licensing matters if you are on an older LTS. Oracle plans to offer JDK 21 updates released after September 2026 under the Java SE OTN license, and tells users who want permissive licensing to move to Oracle JDK 25 or later. A vendor-neutral OpenJDK build such as Temurin avoids that question entirely.
| Version | Type | Use it for |
|---|---|---|
| JDK 21 | LTS | Existing services not yet migrated |
| JDK 25 | LTS | New projects (default choice) |
| JDK 27 | Feature release | Experiments, tracking upcoming features |
Pick a JDK Distribution
All major distributions build from the same OpenJDK source. They differ in support terms, packaging, and extras.
| Distribution | Vendor | Cost | Best for |
|---|---|---|---|
Temurin (-tem) |
Eclipse Adoptium | Free | General-purpose default |
Corretto (-amzn) |
Amazon | Free | AWS-hosted workloads |
Zulu (-zulu) |
Azul | Free tier | Wide platform coverage |
GraalVM (-graalce) |
Oracle/community | Free CE | Native images, polyglot |
Oracle JDK (-oracle) |
Oracle | Free for all users for JDK 25 | Teams standardized on Oracle |
This guide uses Temurin. Every command below works with any other vendor if you swap the identifier.
Install the JDK Without a Version Manager
Use a native package manager if you only need one JDK.
Windows
# Install Temurin 25 with winget
winget install EclipseAdoptium.Temurin.25.JDK
# Open a NEW terminal, then verify
java -version
javac -version
The Adoptium installer can also set JAVA_HOME and the PATH entry for you. Tick those options if you use the MSI instead.
macOS
# Install Temurin 25 via Homebrew
brew install --cask temurin@25
# Locate it and export JAVA_HOME for the current shell
export JAVA_HOME=$(/usr/libexec/java_home -v 25)
java -version
The /usr/libexec/java_home utility is the macOS-native way to resolve an installed JDK by version.
Linux (Debian/Ubuntu)
# Install the OpenJDK 25 package if your release packages it
sudo apt update
sudo apt install openjdk-25-jdk
# Verify both the runtime and the compiler
java -version
javac -version
If your distribution does not package JDK 25 yet, use SDKMAN in the next section or Adoptium’s package repository.
Both java -version and javac -version must print a version. A missing javac means you installed a JRE, not a JDK.
Manage Multiple JDKs With SDKMAN
SDKMAN installs JDKs under ~/.sdkman/candidates and switches them by editing your shell environment. It works on macOS, Linux, and WSL. Windows users should run it inside WSL or use winget plus JAVA_HOME.
Install SDKMAN
# Prerequisites on Debian/Ubuntu
sudo apt install curl zip unzip ca-certificates -y
# Install SDKMAN
curl -s "https://get.sdkman.io" | bash
# Load it into the current shell
source "$HOME/.sdkman/bin/sdkman-init.sh"
# Confirm
sdk version
Install and Switch JDKs
Running sdk install java installs the latest stable Java version. To pin a vendor and version, copy an identifier from sdk list java.
# List every available JDK, grouped by vendor
sdk list java
# Install a specific Temurin build (identifier comes from the list)
sdk install java 25.0.3-tem
# Install a second JDK for legacy work
sdk install java 21.0.11-tem
# Switch for the current shell session only
sdk use java 21.0.11-tem
# Make a version the default for all new shells
sdk default java 25.0.3-tem
# Show what is active
sdk current java
The identifier format is <version>-<vendor>. The version numbers above are examples. Use the ones your own sdk list java prints.
sdk use affects only the current terminal. sdk default persists. Mixing them up is the most common SDKMAN support question.
Pin a Version Per Project With .sdkmanrc
Commit an .sdkmanrc file so every contributor uses the same toolchain.
# Generate a file from your current versions
sdk env init
# .sdkmanrc
java=25.0.3-tem
maven=3.9.11
# Install anything missing and activate the versions
sdk env install
With an .sdkmanrc present, sdk env install installs missing SDKs and switches the current shell to the pinned versions. To switch automatically on cd, set sdkman_auto_env=true in ~/.sdkman/etc/config.
Set JAVA_HOME and PATH
Build tools and IDEs look for JAVA_HOME first. SDKMAN sets it for you. For manual installs, set it yourself.
# ~/.zshrc or ~/.bashrc (Linux example)
export JAVA_HOME="/usr/lib/jvm/java-25-openjdk-amd64"
export PATH="$JAVA_HOME/bin:$PATH"
# Windows: persist for your user account
setx JAVA_HOME "C:\Program Files\Eclipse Adoptium\jdk-25"
# Then add %JAVA_HOME%\bin to your user PATH via System Properties
JAVA_HOME must point to the JDK root directory. It must not point to the bin folder.
Run Your First Program
Java 25 lets you write a runnable file without a class wrapper, and the source launcher compiles and runs it in one step.
// Hello.java
void main() {
// Instance main method: no class, no static, no String[] args
IO.println("Java " + Runtime.version().feature() + " is working.");
}
java Hello.java
Expected output:
Java 25 is working.
The java launcher compiles Hello.java in memory and runs it. No .class file is written. Use a normal class with public static void main(String[] args) once your project has more than one file.
Choose and Configure a Build Tool
Both tools compile, test, and package Java. Pick one per project.
| Feature | Maven | Gradle |
|---|---|---|
| Config format | XML (pom.xml) |
Kotlin or Groovy DSL |
| Learning curve | Lower, fixed lifecycle | Higher, more flexible |
| Incremental builds | Limited | Strong (build cache) |
| JDK pinning | maven.compiler.release |
Toolchains |
| Typical fit | Enterprise, convention-driven | Multi-module, Android, custom pipelines |
On versions: one October 2026 comparison reports Maven 3.10.0 as the recommended stable release, and describes Maven 4 as still under development and not safe for production use. Check Apache’s release page before you commit to a major line.
Maven Setup
sdk install maven
mvn -version # confirms Maven AND the JDK it found
<!-- pom.xml -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.example</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<properties>
<!-- Compile against the Java 25 API and emit Java 25 bytecode -->
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
mvn clean verify
Use maven.compiler.release instead of separate source and target values. It also restricts the compiler to the target version’s public API, so you cannot call a newer method by accident.
Gradle Setup
Gradle’s version must be compatible with your JDK. Gradle 9.0 requires Java 17 or newer to run. Gradle 9.1.0 added support for Java 25. Use the Gradle wrapper so the version travels with the repository.
# Generate the wrapper once
gradle wrapper --gradle-version=9
# Always build through the wrapper
./gradlew build
// build.gradle.kts
plugins {
java
}
java {
toolchain {
// Gradle finds or downloads a matching JDK for compilation
languageVersion = JavaLanguageVersion.of(25)
}
}
repositories {
mavenCentral()
}
// settings.gradle.kts
plugins {
// Auto-provisions the toolchain JDK when it is missing
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}
rootProject.name = "demo"
A toolchain decouples the JDK that runs Gradle from the JDK that compiles your code. A teammate with JDK 21 installed can still build your Java 25 project.
Choose an IDE
| IDE | Strength | Weakness | Best for |
|---|---|---|---|
| IntelliJ IDEA | Deep refactoring, Maven/Gradle sync | Heavier on memory | Professional Java and Kotlin work |
| VS Code + Java extensions | Light, fast startup, remote dev | Fewer refactoring tools | Polyglot developers, containers |
| Eclipse | Mature, plugin-rich | Dated UI conventions | Legacy and OSGi projects |
| NetBeans | Simple, Maven-first | Smaller ecosystem | Learners, small projects |
On currency: IntelliJ IDEA 2026.2 adds day-one support for Java 27 and Kotlin 2.4. Whatever you pick, tell the IDE which JDK to use.
Point the IDE at Your JDK
- IntelliJ IDEA: Open File → Project Structure → SDKs, add your JDK home, then set the Project SDK and Language level. The IDE can also download a JDK directly.
- VS Code: Install the Extension Pack for Java. Set
java.jdt.ls.java.homefor the language server andjava.configuration.runtimesfor project JDKs.
// .vscode/settings.json
{
"java.configuration.runtimes": [
{
"name": "JavaSE-25",
"path": "/home/dev/.sdkman/candidates/java/25.0.3-tem",
"default": true
}
]
}
Keep the IDE’s JDK, the build tool’s JDK, and the CI JDK on the same major version. Mismatches cause “works in the IDE, fails in the pipeline” bugs.
Bad Setup vs. Good Setup
Anti-pattern: Unpinned, Machine-Specific Config
<!-- Bad: relies on whatever JDK happens to be installed -->
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
# Bad: hard-coded path that breaks on every other machine
export JAVA_HOME=/Users/alex/Downloads/jdk-25-temp
Problems:
source/targetdo not limit API usage, so you can compile against methods missing on the target runtime.- The hard-coded download path exists on one laptop.
- Nothing tells a new teammate which JDK to install.
Refactored: Reproducible Config
<!-- Good: one property, API-checked -->
<properties>
<maven.compiler.release>25</maven.compiler.release>
</properties>
# Good: .sdkmanrc committed to the repo
java=25.0.3-tem
maven=3.9.11
# Good: new contributor onboarding is two commands
sdk env install
mvn clean verify
The refactored version moves the Java version into the repository. Onboarding drops from a wiki page to two commands.
Troubleshooting Common Failures
| Symptom | Cause | Fix |
|---|---|---|
javac: command not found |
JRE installed, not a JDK | Install the -jdk package |
java -version shows an old version |
Older JDK earlier on PATH |
Run which -a java and reorder PATH |
Unsupported class file major version 69 |
Tool is older than Java 25 | Upgrade the tool, or use a toolchain to run it on an older JDK |
sdk: command not found |
Init script not sourced | Add the sdkman-init.sh line to your shell profile |
| Gradle ignores your JDK | JAVA_HOME unset or wrong |
Check ./gradlew --version |
Java 25 requires Gradle 9.1.0 or later, according to Gradle’s compatibility matrix. Class file major version 69 corresponds to Java 25, so that error means a tool in your chain cannot read Java 25 bytecode yet. Maven plugins, code-coverage agents, and bytecode libraries are the usual culprits.
Verify the Whole Toolchain
Run this checklist after setup. Every command should succeed.
java -version # runtime version
javac -version # compiler version
echo $JAVA_HOME # points to the JDK root
mvn -version # Maven reports the same JDK
./gradlew --version # Gradle reports the same JDK (inside a Gradle project)
If any tool reports a different JDK than the others, fix JAVA_HOME before you write code.
FAQ
Which JDK should I install in 2026?
Install JDK 25 (LTS). It is the current long-term-support release, and Oracle lists premier support until September 2030. Use JDK 27 only to test new features, since it is a six-month release.
Is the JDK free to download and use?
Yes. Temurin, Corretto, and Zulu are free OpenJDK builds. Oracle also provides Oracle JDK 25 free for all users under its no-fee license. Check each vendor’s license text before you ship commercial products.
What is the difference between the JDK and the JRE?
The JDK includes the compiler (javac) and development tools plus a runtime. A JRE only runs compiled programs. Modern distributions ship the JDK, and you need it to build code.
Should I use SDKMAN or install Java manually?
Use SDKMAN if you work on more than one Java version or share projects through an .sdkmanrc file. A single native install through winget, Homebrew, or apt is enough if you only ever need one JDK.




