Install the JDK and Set Up Java: IDEs, SDKMAN, and Build Tools

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.release in Maven and toolchains in Gradle, so teammates and CI compile with the same JDK.
  • Set JAVA_HOME once. 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.home for the language server and java.configuration.runtimes for 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/target do 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.

Hot this week

Humanoids in Factories and Warehouses: What They Actually Do Today

Which humanoid robots do real work in factories and warehouses today? See deployment data, ROI math and ROS 2 code. Read the 2026 guide.

Debugging Robot Code: Logs, Serial Output, rosbag, and Foxglove

Debug robot code faster with ROS 2 logging, serial capture, rosbag2 recording, and Foxglove. Copy the configs and scripts into your stack today.

Build a Mapping Robot With SLAM From Scratch

Build a SLAM mapping robot from scratch: wiring, odometry, LiDAR, ROS 2 slam_toolbox config and tuning. Follow the full guide and map your first room.

Depth Cameras: Stereo, Time-of-Flight, and Structured Light Compared

Compare stereo, time-of-flight, and structured light depth cameras: accuracy, range, sunlight, ROS2 setup. Pick the right sensor for your robot.

Python vs C++ for Robotics: Which Should You Use?

Python vs C++ for robotics compared: latency, ROS2 performance, control loops, and code examples. Learn which language fits your robot. Read the guide.

Topics

Humanoids in Factories and Warehouses: What They Actually Do Today

Which humanoid robots do real work in factories and warehouses today? See deployment data, ROI math and ROS 2 code. Read the 2026 guide.

Debugging Robot Code: Logs, Serial Output, rosbag, and Foxglove

Debug robot code faster with ROS 2 logging, serial capture, rosbag2 recording, and Foxglove. Copy the configs and scripts into your stack today.

Build a Mapping Robot With SLAM From Scratch

Build a SLAM mapping robot from scratch: wiring, odometry, LiDAR, ROS 2 slam_toolbox config and tuning. Follow the full guide and map your first room.

Depth Cameras: Stereo, Time-of-Flight, and Structured Light Compared

Compare stereo, time-of-flight, and structured light depth cameras: accuracy, range, sunlight, ROS2 setup. Pick the right sensor for your robot.

Python vs C++ for Robotics: Which Should You Use?

Python vs C++ for robotics compared: latency, ROS2 performance, control loops, and code examples. Learn which language fits your robot. Read the guide.

Build a ROS 2 Rover: Raspberry Pi 5, Motors, and LiDAR

Build a ROS 2 rover with Raspberry Pi 5, RPLIDAR C1, and a Pico motor controller. Copy the code, wire it, and map your room. Start building now.

Imitation Learning for Robots: Teach by Demonstration

Learn imitation learning for robots: behavior cloning, DAgger, ACT, and diffusion policies with ROS2 code. Build your first policy today.

LiDAR for Robots: 2D, 3D, and Solid-State Compared

Compare 2D, 3D, and solid-state LiDAR for robots. See specs, ROS2 configs, code, and a selection workflow. Pick the right sensor now.

Related Articles

Popular Categories