Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Java  Module 1 – Start here: JDK 25 LTS and your first programs

Install JDK 25 and choose a JDK build

Install a JDK 25 build, check it with java -version and javac -version, compare vendor builds by licence and updates, and set PATH and JAVA_HOME.

  • Beginner
  • 20 minutes
  • Examples run with Java 25.0.4.1 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 20 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Choose a JDK 25 build by its published licence terms and how long it receives updates
  • Install a JDK 25 LTS build and confirm it with java -version and javac -version
  • Read a Java version string such as 25.0.4.1+1-LTS part by part
  • Configure PATH and JAVA_HOME, or pin a JDK version per project with mise
  • Diagnose "release version 25 not supported" from the JDK that a tool runs

Before you start

What you’ll learn · Before you start

What you will learn

  • Choose a JDK 25 build by its published licence terms and how long it receives updates
  • Install a JDK 25 LTS build and confirm it with java -version and javac -version
  • Read a Java version string such as 25.0.4.1+1-LTS part by part
  • Configure PATH and JAVA_HOME, or pin a JDK version per project with mise
  • Diagnose "release version 25 not supported" from the JDK that a tool runs

Before you start

On this page

To write Java you install a JDK: The Java Development Kit: a JVM, the standard library and the tools for writing Java, among them the compiler javac, the java launcher, the disassembler javap and JShell. More in “What Java is, how it runs and where it is used”, and for this track that means JDK 25. Once it is installed, two commands tell you whether it worked: java -version and javac -version must both report 25. Several vendors publish builds of JDK 25, and every one of them runs the same programs. What sets them apart is the licence and how long each keeps sending updates, so those two facts decide which build you install. For learning, for college labs and for most projects, Eclipse Temurin 25 from the Adoptium project is a sound choice: it is open source, costs nothing, receives updates until at least 2031, and it is the JDK that this track’s examples run on. The last step is to make your terminal, your IDE and your build tool use the same JDK, through PATH: An environment variable that lists folders in order. A terminal runs the first program of the name you type, such as java or javac, that it finds in those folders., JAVA_HOME: An environment variable that names the folder of a JDK, the one that holds bin. Build tools such as Maven and Gradle use the JDK it names before the java found on PATH. or a version pinned for each project.

Builds of JDK 25 differ in licence and updates, not in behaviour

All of these builds come from the OpenJDK: The open-source project whose JDK releases are the reference implementation of each Java SE version. Eclipse Adoptium (Temurin), Oracle and other vendors build their JDKs from its source code. More in “What Java is, how it runs and where it is used” source code. These three are the ones you are most likely to meet:

  • Temurin 25, built by the Adoptium project of the Eclipse Foundation. Its licence is the GPL, version 2, with the Classpath Exception: open source, with no fee. It receives updates until at least 2031. It suits learning, college labs, most teams and CI servers.
  • Oracle JDK 25, built by Oracle. It comes under Oracle’s No-Fee Terms and Conditions until one year after JDK 29 ships; later updates come under Oracle’s OTN licence. It suits organisations that use Oracle’s own JDK, often with an Oracle support contract.
  • OpenJDK 25 from jdk.java.net, plain OpenJDK builds that Oracle publishes. The licence is the same as Temurin’s, but updates stopped when JDK 26 replaced it, and the page now marks JDK 25 as superseded. It suits only trying the newest feature release during its six months.

The licence terms matter more than they first appear to. Since JDK 17, Oracle’s support roadmap has offered each LTS release of Oracle JDK at no cost to all users until one year after the next LTS appears. After that, new updates of that release come under the Oracle Technology Network (OTN) licence, which allows use at no cost only for personal and development purposes. The roadmap moves the updates of Oracle JDK 21 to the OTN licence once its overlap year with JDK 25 is over, and plans the same for Oracle JDK 25 a year after JDK 29. So on a college lab computer or at work, check which build is installed before you rely on it.

Temurin avoids that question. The Adoptium FAQ gives its licence as the GNU General Public License, version 2, with the Classpath Exception, says the builds cost nothing, and states that every Temurin release has passed Oracle’s Java Compatibility Kit, the test suite that checks a build against the Java SE: Java Platform, Standard Edition: the specification of the language (the JLS), of class files and the JVM (the JVMS) and of the standard API, one version for every feature release, such as Java SE 25. More in “What Java is, how it runs and where it is used” specification. Microsoft, Azul, Red Hat and other vendors also publish builds of their own, each with its own support periods and paid support offers. Answer two questions about your own use, and the table marks the builds that fit:

Interactive · answer and compare Which JDK 25 build fits your case? Answer the two questions about how you will use the JDK. Each answer marks the builds that no longer fit, or fit with a caveat, and says why.
How long must this JDK keep receiving updates?
Will the JDK be used for more than personal use and development?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Three builds of JDK 25 against their licence, their updates and the use each suits
Build Licence Updates Suits
Temurin 25 Published by: Eclipse Adoptium Good GPL version 2 with the Classpath Exception: open source, no fee Good until at least 2031, on Adoptium's support roadmap Good learning, college labs, most teams and CI servers
Oracle JDK 25 Published by: Oracle Mixed no-fee terms until a year after JDK 29 ships, then the OTN licence for later updates Good long term, from Oracle; the later ones under the OTN licence Mixed organisations that use Oracle's own JDK, often with a support contract
OpenJDK 25 from jdk.java.net Published by: Oracle, as plain OpenJDK builds Good the same licence as Temurin's Poor stopped when JDK 26 replaced it; the page marks JDK 25 as superseded Poor only trying the newest feature release during its six months
How the answers decide
  • “How long must this JDK keep receiving updates?” For years: rules out OpenJDK 25 from jdk.java.net. Oracle's jdk.java.net builds cover only the current feature release, so the updates of JDK 25 there stopped when JDK 26 replaced it.
  • “Will the JDK be used for more than personal use and development?” Yes, for example to run a service: adds a caveat to Oracle JDK 25. Updates published from a year after JDK 29 come under the OTN licence, which allows use at no cost only for personal and development purposes.
  • “How long must this JDK keep receiving updates?” A few months, to try a release: adds a caveat to OpenJDK 25 from jdk.java.net. jdk.java.net now offers the newest feature release, JDK 27; its JDK 25 build is superseded and receives no more updates, even for a short trial.

In short: Temurin 25 fits nearly every case, Oracle JDK 25 fits organisations that work with Oracle’s JDK and keep its licence terms in view, and the jdk.java.net build of JDK 25 is ruled out for anything that needs updates, because it receives none.

The same program shows the difference between two JDK build: One vendor's compiled JDK of a release, such as Eclipse Temurin 25.0.4.1 or Oracle JDK 25. Every build of a release runs the same programs; the licence, the update period and the platforms covered differ. of JDK 25 on one computer: Temurin 25.0.4.1, and the OpenJDK 25.0.2 build that Oracle published on jdk.java.net:

Build.java: what a build says about itself Java · Build.java
// Prints what this JDK build says about itself.
void main() {
    Runtime.Version version = Runtime.version();
    boolean lts = version.optional().map(text -> text.startsWith("LTS")).orElse(false);
    IO.println("version:        " + version);
    IO.println("feature/update: " + version.feature() + " / " + version.update());
    IO.println("marked LTS:     " + lts);
    IO.println("vendor:         " + System.getProperty("java.vendor"));
    IO.println("vendor build:   " + Objects.requireNonNullElse(System.getProperty("java.vendor.version"), "(none)"));
}
Two builds of JDK 25 Python · builds_session.py
from session import run

# One program, two builds of JDK 25 from two vendors.
run("java Build.java")
run("java Build.java", jdk="25-jdk.java.net")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java Build.java
version:        25.0.4.1+1-LTS
feature/update: 25 / 4
marked LTS:     true
vendor:         Eclipse Adoptium
vendor build:   Temurin-25.0.4.1+1
# JDK in use: openjdk version "25.0.2"
$ java Build.java
version:        25.0.2+10-69
feature/update: 25 / 2
marked LTS:     false
vendor:         Oracle Corporation
vendor build:   (none)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 builds_session.py

Both run Java 25, but the Temurin build is two updates ahead and is marked LTS in its version, which is how a vendor says that it supports the release for the long term. Oracle’s OpenJDK builds on jdk.java.net cover only the current feature release, so 25.0.2 received no further updates there once JDK 26 was out.

Checkpoint

Check: Choosing a JDK 25 build

  1. Question 1 of 2 A college lab needs one JDK 25 build that costs nothing for every use, students' and staff's alike, and is updated until at least 2031. Which build fits?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Temurin 25

    The lab's two needs rule out the other builds: jdk.java.net stopped updating JDK 25, and Oracle JDK 25's later updates move to the OTN licence. Temurin 25 is open source, has no fee and is updated until at least 2031.

  2. Question 2 of 2 When do new updates of Oracle JDK 25 come under the OTN licence?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: One year after JDK 29 ships

    Since JDK 17, Oracle's roadmap offers each LTS release of Oracle JDK at no cost to all users until one year after the next LTS appears. For JDK 25 that is a year after JDK 29; later updates come under the OTN licence.

Installing takes one installer or one command

Use one of these routes, then check the installation as the next section shows:

  • Windows. Run winget install EclipseAdoptium.Temurin.25.JDK in a terminal, or download the .msi installer from adoptium.net. The installer puts Temurin in C:\Program Files\Eclipse Adoptium\ and adds it to PATH by default; setting JAVA_HOME is an extra feature that you switch on in its Custom Setup screen. Switch it on.
  • macOS. Download the .pkg installer from adoptium.net and open it. Temurin goes into /Library/Java/JavaVirtualMachines/temurin-<version>.jdk/, and the JDK’s own folder, the one JAVA_HOME names, is Contents/Home inside it.
  • Linux. Add Adoptium’s package repository as its Linux page describes, then install the package temurin-25-jdk with your package manager: sudo apt install temurin-25-jdk on Debian and Ubuntu, sudo dnf install temurin-25-jdk on Fedora and Red Hat, sudo zypper install temurin-25-jdk on openSUSE or sudo apk add temurin-25-jdk on Alpine.
  • Any system, one JDK per project. The version manager mise installs JDKs per project: in a project folder, mise use java@temurin-25 installs the newest Temurin 25 and records the choice in the project’s mise.toml. Name the exact build, mise use java@temurin-25.0.4+101.0.LTS, when everyone must run precisely the same one.

Installer screens and package names can change between releases; when a step looks different, follow the vendor’s installation page for your system. Whichever route you take, the steps after it are the same. Step through them, including the way back when a check reports another version:

Interactive · stage by stage Install a JDK 25, then check it Step through an install from the choice of route to the two checks, and the way back when a check reports another version.
Install a JDK 25, then check it, step 7 of 7. Showing Pick your route, Install Temurin 25, Open a new terminal, java -version, javac -version, Ready to compile. In focus: Ready to compile.not 25: fix PATHPick your routeinstaller, package or miseInstall Temurin 25one installer or one commandOpen a new terminalold ones keep old settingsjava -versionmust report 25javac -versionmust report 25Ready to compileboth report 25

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. Pick a route. Choose one route for your system, the Windows installer or winget, the macOS installer package, the temurin-25-jdk package on Linux, or mise for one JDK per project.
  2. Install it. Install Temurin 25. On Windows, switch on the JAVA_HOME feature in the installer's Custom Setup screen; on macOS the JDK goes into /Library/Java/JavaVirtualMachines/.
  3. A new terminal. Open a new terminal. A terminal that was opened before the install still has the old settings, so it may not find the new JDK.
  4. Check java. Run java -version. Its first line must name version 25, as in openjdk version "25.0.4.1" LTS.
  5. Check javac. Run javac -version. It prints one line, such as javac 25.0.4.1, and it must report 25 as well.
  6. Not 25? Go back. If either command reports another version, or command not found, the java that the terminal finds is not the JDK you installed. Fix PATH as a later section shows, open a new terminal and check again.
  7. Ready. When both commands report 25, the JDK is ready, and the next lesson compiles and runs its first program with it.

Checkpoint

Check: Installing a JDK

  1. Question 1 of 2 You installed Temurin 25, but java -version in a terminal that was already open still reports 21. What do you try first?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Open a new terminal and run the check again

    Installers change PATH and JAVA_HOME for terminals started afterwards. Open a new terminal and run both checks again; only if they still report 21 is PATH or JAVA_HOME the problem.

  2. Question 2 of 2 On macOS, Temurin is installed in /Library/Java/JavaVirtualMachines/temurin-<version>.jdk/. Which folder does JAVA_HOME name?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Its Contents/Home folder

    JAVA_HOME names a JDK's own folder, the one that holds bin. On macOS that is Contents/Home inside the temurin-<version>.jdk folder; its bin folder is what goes first on PATH.

The launcher and the compiler must both report 25

Open a new terminal (one opened before the install still has the old settings) and run the two checks, java -version for the launcher and javac -version for the compiler. Here they are with JDK 25 first on PATH, and then with JDK 21, which is what you would see if an older JDK came first:

java -version and javac -version Python · versions_session.py
from session import run

# The check after an install: the launcher and the compiler, first with JDK 25 on PATH, then with JDK 21.
run("""
java -version
javac -version
""")
run("""
java -version
javac -version
""", jdk="21")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java -version
openjdk version "25.0.4.1" LTS
OpenJDK Runtime Environment Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS, mixed mode, sharing)
$ javac -version
javac 25.0.4.1
# JDK in use: openjdk version "21.0.12.1" LTS
$ java -version
openjdk version "21.0.12.1" LTS
OpenJDK Runtime Environment Temurin-21.0.12.1+1 (build 21.0.12.1+1-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.12.1+1 (build 21.0.12.1+1-LTS, mixed mode, sharing)
$ javac -version
javac 21.0.12.1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 versions_session.py

Read the three lines of java -version from the top:

  1. openjdk version "25.0.4.1" LTS: the version, and LTS because this build has long-term support. The real line also shows the build’s release date after the version, which these sessions leave out.
  2. OpenJDK Runtime Environment Temurin-25.0.4.1+1: the vendor’s name for the build, here Temurin.
  3. OpenJDK 64-Bit Server VM ... mixed mode, sharing: the JVM. Mixed mode is the interpreter with the JIT compiler from lesson 1, and sharing means it started from a class data sharing archive, a ready-made image of about 1,300 core library classes that shortens start-up.

javac -version prints one line. If either command reports something other than 25, or command not found, the java that your terminal finds is not the JDK you installed; the section on how each tool chooses a JDK, below, fixes that.

-version writes to standard error, –version to standard output

The two spellings print almost the same text to different places. The java documentation says that -version prints to the error stream and --version to the output stream, and that matters as soon as a script reads the version:

Where the version text goes Python · version_options_session.py
from session import run

# -version writes to standard error and --version to standard output; the last line of -version names the JVM's modes.
run("""
java -version 2>/dev/null
java --version 2>/dev/null
java -version 2>&1 | head -n 1
java -Xshare:off -version 2>&1 | tail -n 1
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java -version 2>/dev/null
$ java --version 2>/dev/null
openjdk 25.0.4.1 LTS
OpenJDK Runtime Environment Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS, mixed mode, sharing)
$ java -version 2>&1 | head -n 1
openjdk version "25.0.4.1" LTS
$ java -Xshare:off -version 2>&1 | tail -n 1
OpenJDK 64-Bit Server VM Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS, mixed mode)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 version_options_session.py

With standard error thrown away (2>/dev/null), -version prints nothing at all, while --version still prints its three lines, starting openjdk 25.0.4.1 without the word “version”. A script that reads java -version must redirect standard error into the pipe with 2>&1, as the third command does. The last command switches class data sharing off, and the word sharing disappears from the JVM’s line.

Reading java -version through a pipe

java -version | head -n 1 prints nothing, because the text goes to standard error and only standard output enters the pipe. Write java -version 2>&1 | head -n 1, or read java --version, which prints to standard output.

Checkpoint

Check: Checking java and javac

  1. Question 1 of 2 The third line of java -version ends in mixed mode, sharing). What does sharing say?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The JVM started from a class data sharing archive of about 1,300 core library classes

    Sharing means class data sharing: the JVM started from a ready-made image of about 1,300 core library classes, which shortens start-up. java -Xshare:off -version prints the same line without the word.

  2. Question 2 of 2 A script runs java -version | head -n 1 and gets no output at all. What fixes it?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: java -version 2>&1 | head -n 1

    The java documentation says -version prints to the error stream and --version to the output stream. A pipe carries standard output only, so either redirect with 2>&1 or read java --version.

A Java version is four numbers, a build number and a label

Since JDK 10, a Java version follows the scheme of JEP 322: up to four numbers, then a build number and an optional label. Temurin’s full version, 25.0.4.1+1-LTS, reads like this:

  • 25 is the feature release; it goes up by one every six months.
  • 0 is the interim number, reserved for releases between feature releases; under the current timetable it stays 0.
  • 4 is the update: the fourth quarterly update of JDK 25.
  • 1 is the patch: an extra release on top of update 4, for an urgent fix.
  • +1 is the build number.
  • -LTS is a label: the vendor supports this release for the long term.

Step through the same parts one at a time, then see how they read in the first build of JDK 27:

Interactive · step by step 25.0.4.1+1-LTS, one part at a time Step through the six parts of Temurin's full version, then see how the same parts read in 27+35, the first build of JDK 27.
25.0.4.1+1-LTS, one part at a time, step 8 of 8. Showing Feature (27), Interim (0, left out), Update (0, left out), Patch (0, left out), Build (+35), Label (none). In focus: Feature, Interim, Update, Patch, Build.Feature27Interim0, left outUpdate0, left outPatch0, left outBuild+35Labelnone

The drawing shows the whole scene; its 8 steps are listed below.

Every step as text
  1. The feature release. Since JDK 10 a Java version follows JEP 322, up to four numbers, then a build number and an optional label. The first number, 25, is the feature release, which goes up by one every six months.
  2. The interim number. The second number, 0, is the interim number, reserved for releases between feature releases. Under the current timetable it stays 0.
  3. The update. The third number, 4, is the update. This build belongs to the fourth quarterly update of JDK 25.
  4. The patch. The fourth number, 1, is the patch, an extra release on top of update 4 for an urgent fix.
  5. The build number. After the plus sign comes the build number, here 1.
  6. The label. The label -LTS says that the vendor supports this release for the long term. Oracle's OpenJDK 25.0.2 build carries no such label, as Build.java showed.
  7. Zeros left out. Zeros at the end are left out, so the first release of JDK 27 is simply 27, and Temurin's first build of it is 27+35, feature release 27 and build 35, with no label.
  8. Read it in code. A program reads the parts with Runtime.Version, through feature(), interim(), update(), patch() and build(), instead of taking the text apart by hand.

Zeros at the end are left out, so the first release of JDK 27 is simply 27, and Temurin’s first build of it is 27+35. The java.lang.Runtime.Version class reads these parts for a program: feature(), interim(), update(), patch() and build(), as Build.java does above.

Key idea

In 25.0.4.1+1-LTS, 25 is the feature release, 0 the interim number, 4 the update and 1 the patch, then come the build number and the label.

Checkpoint

Check: Reading a version string

  1. Question 1 of 2 In 25.0.4.1+1-LTS, what does the 1 right after the 4 mean?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The patch, an extra release on top of update 4 for an urgent fix

    25 is the feature release, 0 the interim number, 4 the update and 1 the patch, an extra release for an urgent fix. The build number, 1, follows the plus sign, and -LTS is the label.

  2. Question 2 of 2 Temurin 21's version in the session is 21.0.12.1+1-LTS. What is its update number?

    Type a number.

    A hint

    The update is the third number.

    Show the answer: Question 2 of 2

    Answer: 12

    21 is the feature release, 0 the interim number and 12 the update, so this is the twelfth quarterly update of JDK 21, with one patch (the 1) on top.

The terminal, build tools and the IDE each choose a JDK

A computer can hold several JDKs at once, and each tool decides for itself which one to run:

Three places that choose a JDK, checked in turn: the terminal (PATH), build tools (JAVA_HOME) and the IDE; all should name one JDK 25.1. Your terminalruns the first java and javacfound in the folders of PATH2. Maven, Gradle and other build toolsuse JAVA_HOME if it is set,otherwise the java on PATH3. Your IDEuses its own JDK settingfor each projectAll three name one JDK 25,for example Temurin 25.0.4.1then checkthen check

Three places that choose a JDK

Text description of the diagram

The diagram lists, from top to bottom, the three places that decide which JDK runs, in the order in which to check them. All three should name the same JDK 25, for example Temurin 25.0.4.1.

  1. Your terminal runs the first java and javac that it finds in the folders listed in PATH.
  2. Maven, Gradle and other build tools use the JDK that JAVA_HOME names when the variable is set, and otherwise the java found on PATH.
  3. Your IDE uses its own JDK setting for each project, which does not have to match either of the other two.
  • Your terminal runs the first java it finds while searching the folders of PATH, in order. In a macOS or Linux shell, command -v java prints which file that is; in the Windows Command Prompt, where java lists every match in order.
  • Build tools look at JAVA_HOME first. Maven’s installation guide asks for either JAVA_HOME or java on PATH, and the Android documentation describes the same order for Gradle run from a terminal: JAVA_HOME if it is set, otherwise the java on PATH.
  • Your IDE has a JDK setting of its own for each project, which matches neither of the other two unless you choose the same JDK there.

The JVM can report where its own JDK is installed. java.home is the folder that JAVA_HOME should name, the one that holds bin:

Which java, and where its JDK lives Python · where_session.py
from session import run

# Which java is first on PATH, and where its JDK lives.
run("""
command -v java
java -XshowSettings:properties -version 2>&1 | grep -E "java\\.(home|vendor|version) "
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ command -v java
<JDK folder>/bin/java
$ java -XshowSettings:properties -version 2>&1 | grep -E "java\.(home|vendor|version) "
    java.home = <JDK folder>
    java.vendor = Eclipse Adoptium
    java.version = 25.0.4.1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 where_session.py

The session writes the JDK’s own folder as <JDK folder>, because its real name differs from one computer to the next; on yours it is a real path, such as the Contents/Home folder of a macOS install. command -v java names the bin/java inside it, and java.home names the folder itself.

To set both variables yourself, for example after unpacking a JDK from an archive, point JAVA_HOME at the JDK’s folder and put its bin folder first on PATH. In a macOS or Linux shell, add export JAVA_HOME=/path/to/jdk-25 and export PATH="$JAVA_HOME/bin:$PATH" to your shell’s start-up file (~/.zshrc or ~/.bashrc). On Windows, open System Properties > Environment Variables, set JAVA_HOME to the JDK’s folder, and add %JAVA_HOME%\bin near the top of Path. Then open a new terminal and run the two checks again.

“release version 25 not supported” means an older javac ran

The most common symptom is a compiler that is older than the release a project asks for. Here the same command runs first with the javac of JDK 21 and then with the javac of JDK 25:

release version 25 not supported Python · release_session.py
from session import run

# The same compile command with the javac of JDK 21, then with the javac of JDK 25.
run("javac --release 25 -d out Hello.java", jdk="21", expect_failure=["javac --release 25 -d out Hello.java"])
run("""
javac --release 25 -d out Hello.java
java -cp out Hello
""")

Output

# JDK in use: openjdk version "21.0.12.1" LTS
$ javac --release 25 -d out Hello.java
error: release version 25 not supported
Usage: javac <options> <source files>
use --help for a list of possible options
[exit status 2]
# JDK in use: openjdk version "25.0.4.1" LTS
$ javac --release 25 -d out Hello.java
$ java -cp out Hello
Compiled for Java 25

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 release_session.py

error: release version 25 not supported means that the javac which ran does not know Java 25 at all. When an IDE or a build tool prints it while your terminal happily reports 25, that tool is running an older JDK: compare its JDK setting, or the JAVA_HOME it sees, with the output of java -XshowSettings:properties -version in your terminal. Step through such a case, with the messages of the session above:

Interactive · step by step Why a build fails while the terminal reports 25 Step through one compile asked of two JDKs. The terminal and the build tool each choose a JDK by their own rule.
Why a build fails while the terminal reports 25, step 5 of 5. Showing Your terminal, Build tool (JAVA_HOME: JDK 25), JDK 25 (compiled for Java 25), JDK 21 (release 25 not supported). In focus: JDK 25.PATHJAVA_HOMEYour terminalfinds java on PATHBuild toolJAVA_HOME: JDK 25JDK 25compiled for Java 25JDK 21release 25 not supported--release 25

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. The terminal says 25. In the terminal, java -version and javac -version both report 25, because the JDK 25 folder comes first on PATH.
  2. The build tool asks JDK 21. The build tool looks at JAVA_HOME first, and JAVA_HOME still names JDK 21. It asks that JDK's javac to compile for release 25.
  3. javac 21 refuses. The javac of JDK 21 does not know Java 25 at all, so it stops with "error: release version 25 not supported", the first message of the session above.
  4. Point JAVA_HOME at 25. The fix is to make the build tool use JDK 25. Point JAVA_HOME at the JDK 25 folder, or choose JDK 25 in the tool's own setting, then open a new terminal.
  5. javac 25 compiles. Now the javac of JDK 25 compiles the class for release 25, and java runs it, which prints Compiled for Java 25, the session's last line.

A version manager pins the JDK per project

On a computer with several projects, a version manager keeps the choice inside each project. With mise, the command mise use java@temurin-25.0.4+101.0.LTS records that exact build in the project’s mise.toml, and mise then sets JAVA_HOME to it for commands started with mise exec, for its tasks, and in shells where mise is activated. Its documentation adds two cautions: tools that read JAVA_HOME once at start-up, such as an IDE, see a new version only after a restart, and a plain java@25 means the newest Temurin 25, because Temurin is mise’s default vendor for Java. Without a pin, plain java in a new terminal finds whichever JDK comes first on PATH, which may be an older JDK 21 that cannot run the compact source files of the next lesson.

Key idea

The terminal follows PATH, build tools follow JAVA_HOME and the IDE follows its own setting, so make all three name the same JDK 25, or pin it per project.

Checkpoint

Check: Which JDK each tool uses

  1. Question 1 of 2 In a macOS or Linux shell, which command prints the java that the terminal will run?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: command -v java

    The terminal runs the first java in the folders of PATH, and command -v java prints that file. On Windows, where java lists every match in order.

  2. Question 2 of 2 Your terminal reports JDK 25, but Maven compiles with JDK 21. Which setting does Maven most likely follow?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: JAVA_HOME, which still names JDK 21

    Maven's installation guide asks for JAVA_HOME or java on PATH, and when JAVA_HOME is set, it wins. Point JAVA_HOME at JDK 25, open a new terminal, and Maven and the terminal agree.

Practise: the same feature release?

Write sameFeature, which receives the first line of java -version and the line of javac -version, and returns true when both name the same feature release. The four checks use lines recorded in this lesson’s sessions, without the release date. Run java SameFeature.java until every check passes.

SameFeature.java: the exercise Java · SameFeature.java
// Exercise: do java and javac come from the same feature release?
// Write the body of sameFeature, then run: java SameFeature.java
boolean sameFeature(String javaLine, String javacLine) {
    // javaLine is the first line that java -version prints, javacLine the line that javac -version prints.
    return false;
}

void check(String javaLine, String javacLine, boolean expected) {
    boolean got = sameFeature(javaLine, javacLine);
    IO.println((got == expected ? "PASS" : "FAIL") + "  " + javaLine + "  |  " + javacLine + "  ->  " + got);
}

void main() {
    check("openjdk version \"25.0.4.1\" LTS", "javac 25.0.4.1", true);
    check("openjdk version \"21.0.12.1\" LTS", "javac 25.0.4.1", false);
    check("openjdk version \"25.0.2\"", "javac 25.0.4.1", true);
    check("openjdk version \"25.0.4.1\" LTS", "javac 21.0.12.1", false);
}

As given, sameFeature always returns false, so the two checks that expect true fail:

The checks before you start Python · same_feature_session.py
from session import run

# The exercise as given: sameFeature always answers false.
run("java SameFeature.java")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java SameFeature.java
FAIL  openjdk version "25.0.4.1" LTS  |  javac 25.0.4.1  ->  false
PASS  openjdk version "21.0.12.1" LTS  |  javac 25.0.4.1  ->  false
FAIL  openjdk version "25.0.2"  |  javac 25.0.4.1  ->  false
PASS  openjdk version "25.0.4.1" LTS  |  javac 21.0.12.1  ->  false

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 same_feature_session.py

First hint: the version in javaLine is the text between the two quote characters (indexOf('"') and lastIndexOf('"') find them), and in javacLine it is the text after the space. Runtime.Version.parse(...) turns either text into a version whose feature() you can compare.

Then practise the five ideas of the lesson, from choosing a build to the tools that each pick a JDK. The questions adapt to your answers, and every answer comes with its reason:

Practice that adapts to you

Practise this lesson

14 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 14 Of the three JDK 25 builds compared in this lesson, which one does its vendor list with updates until at least 2031?

    Choose one answer.

    Show the answer: Question 1 of 14

    Answer: Eclipse Temurin 25

    Adoptium's roadmap lists Temurin 25 as available until at least 2031. Oracle JDK 25 stays under the no-fee terms until a year after JDK 29 and then moves to the OTN licence, and the jdk.java.net page marks JDK 25 as superseded.

  2. Question 2 of 14 A company wants to run a service on Oracle JDK 25 for many years and keep installing updates at no cost. What should it know first?

    Choose one answer.

    Show the answer: Question 2 of 14

    Answer: Updates from a year after JDK 29 come under the OTN licence, which allows no-cost use only for personal and development purposes

    The roadmap moves the updates of Oracle JDK 21 to the OTN licence once its overlap year with JDK 25 is over, and plans the same for Oracle JDK 25 a year after JDK 29. A service that needs updates for years should plan for that, or use a build such as Temurin.

  3. Question 3 of 14 Build.java printed marked LTS: true on Temurin 25.0.4.1 and false on Oracle's OpenJDK 25.0.2 build. What does the difference mean for you?

    Choose one answer.

    Show the answer: Question 3 of 14

    Answer: Adoptium supports its build for the long term, while the jdk.java.net build received no updates after JDK 26

    The two builds are the same Java 25, but Temurin's carries the LTS label and two more updates. Oracle's OpenJDK builds on jdk.java.net cover only the current feature release, so 25.0.2 was the last one there.

  4. Question 4 of 14 After adding Adoptium's package repository on Debian or Ubuntu, which package installs Temurin 25?

    Choose one answer.

    Show the answer: Question 4 of 14

    Answer: temurin-25-jdk

    Adoptium's Linux packages are called temurin-25-jdk: apt on Debian and Ubuntu, dnf on Fedora and Red Hat, zypper on openSUSE and apk on Alpine.

  5. Question 5 of 14 Everyone in a team must run exactly the same Temurin build in a project. Which mise command records it?

    Choose one answer.

    Show the answer: Question 5 of 14

    Answer: mise use java@temurin-25.0.4+101.0.LTS

    A version manager keeps the choice in the project. Naming the exact build, temurin-25.0.4+101.0.LTS, makes every computer that uses the project run precisely the same JDK.

  6. Question 6 of 14 Why does java -version 2>/dev/null print nothing?

    Choose one answer.

    Show the answer: Question 6 of 14

    Answer: -version writes to standard error, which 2>/dev/null throws away

    The java documentation says that -version prints to the error stream and --version to the output stream. A script that reads the version from java -version must use 2>&1 so that the text reaches the pipe.

  7. Question 7 of 14 Which line of java -version names the vendor's build, such as Temurin-25.0.4.1+1?

    Choose one answer.

    Show the answer: Question 7 of 14

    Answer: The second line, the runtime environment

    The first line is the version, the second the runtime environment with the vendor's build name, here Temurin, and the third the JVM with its mode.

  8. Question 8 of 14 In the version 25.0.4.1+1-LTS, which number is the update release?

    Type a number.

    Show the answer: Question 8 of 14

    Answer: 4

    The parts are feature (25), interim (0), update (4) and patch (1), then the build number after the plus sign and the label LTS. This is the fourth quarterly update of JDK 25, with one extra patch on top.

  9. Question 9 of 14 What does Temurin's version 27+35 tell you?

    Choose one answer.

    Show the answer: Question 9 of 14

    Answer: Feature release 27 and build 35; the interim, update and patch numbers are zeros, left out

    27+35 is feature release 27, build 35. Its interim, update and patch numbers are all 0, and JEP 322 leaves zeros at the end out, so the version has a single number before the plus sign.

  10. Question 10 of 14 A program must check that it runs on Java 25 or later. Which approach is the safest?

    Choose one answer.

    Show the answer: Question 10 of 14

    Answer: Compare Runtime.version().feature() with 25

    Version texts vary: 25.0.4.1+1-LTS, 25.0.2+10-69, 27+35. Runtime.version() returns the parts through feature(), update() and the other accessors, which is safer than taking the text apart by hand.

  11. Question 11 of 14 Which of these decide which JDK a tool uses?

    Choose every answer that is right.

    Show the answer: Question 11 of 14

    Answer:

    • The JAVA_HOME variable
    • The IDE's JDK setting for the project
    • The order of the folders in PATH

    A terminal runs the first java on PATH, build tools look at JAVA_HOME first, and an IDE uses its own JDK setting for each project. Make all three name the same JDK 25.

  12. Question 12 of 14 After an install, java -version reports 25 but javac -version reports 21. What does that tell you?

    Choose one answer.

    Show the answer: Question 12 of 14

    Answer: The java and the javac found on PATH come from two different JDKs

    Each command is found separately on PATH, so a folder of JDK 21 that holds javac can come before the JDK 25 folder. Both checks must report 25; put the JDK 25 bin folder first on PATH, or set JAVA_HOME and PATH to the same JDK.

  13. Question 13 of 14 A build tool fails with error: release version 25 not supported while your terminal shows JDK 25. What is the most likely cause?

    Choose one answer.

    Show the answer: Question 13 of 14

    Answer: The build tool runs an older JDK, for example through a JAVA_HOME that names JDK 21

    The message means the javac that ran does not know release 25. Build tools prefer JAVA_HOME over PATH, so a terminal and a build tool on the same computer can use different JDKs.

  14. Question 14 of 14 You change a project's mise pin from Temurin 21 to Temurin 25, and terminals now report 25, but the IDE that was already open still builds with 21. Why?

    Choose one answer.

    Show the answer: Question 14 of 14

    Answer: Tools that read JAVA_HOME once at start-up, such as an IDE, see a new version only after a restart

    A program reads its environment when it starts. The IDE started while JAVA_HOME still named JDK 21, so it keeps that JDK until it restarts, or until its own JDK setting for the project names JDK 25.

Interview questions

Fresher · What do the numbers in a Java version such as 25.0.4.1+1-LTS mean?

Since JDK 10, versions follow JEP 322. The first number is the feature release, 25, which goes up every six months. The second, interim, is reserved and stays 0 under the current timetable. The third, update, counts the quarterly bug-fix and security updates of that release: this is the fourth. The fourth number, patch, marks an extra release for an urgent fix on top of update 4. After + comes the build number, and a trailing -LTS says that the vendor supports the release for the long term. Zeros at the end are dropped, so the first JDK 27 release is simply 27. In code, Runtime.version() returns these parts through feature(), update() and the other accessors, which is safer than taking the version text apart by hand.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    A college department, or a team of 40 developers, must standardise on one JDK 25 build for about 200 machines and the CI servers, and keep it supported for the next four years. Which builds do you consider, which licence and update questions decide it, and what exactly do you pin?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    On a CI agent, the first build step prints a java -version of 25, but the Maven step then fails with "error: release version 25 not supported". List the places a Java build can take its JDK from, and how you find and fix the one that is wrong.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Builds of JDK 25 run the same programs but differ in licence and in how long updates continue: Temurin 25 is open source and updated until at least 2031, Oracle JDK 25 is at no cost until a year after JDK 29 and then under the OTN licence, and Oracle’s jdk.java.net builds stop at the next feature release.
  • Every route, an installer, a package or mise, ends with the same two checks in a newly opened terminal.
  • java -version and javac -version must both report 25, and -version writes to standard error, so a script reads it with 2>&1.
  • A version such as 25.0.4.1+1-LTS is the feature, interim, update and patch numbers, then the build number and a label.
  • The terminal uses the first java on PATH, build tools prefer JAVA_HOME and an IDE has its own setting, and release version 25 not supported means that the javac which ran is older than JDK 25.

Terms in this lesson

JAVA_HOME
An environment variable that names the folder of a JDK, the one that holds bin. Build tools such as Maven and Gradle use the JDK it names before the java found on PATH.
JDK build
One vendor's compiled JDK of a release, such as Eclipse Temurin 25.0.4.1 or Oracle JDK 25. Every build of a release runs the same programs; the licence, the update period and the platforms covered differ.
PATH
An environment variable that lists folders in order. A terminal runs the first program of the name you type, such as java or javac, that it finds in those folders.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.