Different Ways to Check Java Version in Windows

I’ve lost count of how many “mysterious” Java bugs turned out to be the wrong Java on the PATH. A build that demands Java 21 runs on Java 8. An app compiled with one JDK runs on a different runtime. Or your IDE quietly points at a bundled JRE while your terminal points somewhere else. On Windows, this happens more than you’d think because you can have multiple installs (system-wide, per-user, vendor builds) and Windows resolves executables based on PATH order.

When you check your Java version, you’re really answering two questions:

  • Which java.exe is being launched?
  • What runtime (and often which JDK) does that executable represent?

I’ll walk through practical ways to check Java versions on Windows from the command line, PowerShell, the UI, and by inspecting folders/registry. Along the way I’ll show you how to detect multiple JDKs, confirm whether you have a full JDK (not just a runtime), and avoid the common traps that cause “it works on my machine” headaches.

Java on Windows: JDK, JRE, JVM (why version checks can disagree)

Before I run any commands, I keep the mental model simple:

  • JVM (Java Virtual Machine): the engine that executes Java bytecode. It’s platform-specific (Windows has a Windows JVM build), but you typically don’t install a standalone “JVM” as a separate thing.
  • JRE (Java Runtime Environment): enough to run Java apps: JVM + core libraries. If all you have is a JRE, you can run java, but you usually can’t compile code because javac is missing.
  • JDK (Java Development Kit): what developers want: JRE + compiler + tools (javac, javadoc, jlink, jar, jshell, jcmd, jfr, etc.).

Two practical consequences on Windows:

  • java -version only tells you about the runtime that the launched java.exe belongs to. If your PATH points at an older runtime, you’ll see an older version even if you installed a newer JDK yesterday.
  • javac -version tells you about the compiler. If java and javac come from different folders, you have a mismatch that will eventually bite you (tooling, bytecode level, TLS providers, module behavior).

So I check java, I check javac, and I always confirm the executable location.

A small but important versioning detail: Java 8 vs Java 9+

If you’ve been around Java long enough, you’ve probably seen version strings that look inconsistent:

  • Java 8 often shows 1.8.0_XXX (the “1.” is historical)
  • Java 9+ uses the modern scheme, e.g. 17.0.10 or 21.0.2

This matters when you compare versions in scripts. For example, “1.8” is Java 8, not Java 1.8. If you’re building automation around version checks, prefer printing key/value settings (like java.version and java.home) rather than relying on string comparison heuristics.

Why Windows makes this trickier than you expect

On Windows, Java can come from multiple places at the same time:

  • A classic installer under C:\\Program Files\\...
  • A per-user install under your profile (often C:\\Users\\\\AppData\\Local\\Programs\\...)
  • A portable ZIP you extracted somewhere
  • A build tool that provisions its own JDK (Gradle toolchains, IDE-managed JDKs)
  • A package manager install (Scoop/Chocolatey/winget)

All of those can coexist, and Windows will happily use whichever java.exe it finds first.

Fast checks from Command Prompt (CMD)

CMD is the quickest way to get an answer, especially on machines where PowerShell policies are locked down.

1) Check the runtime version: java -version

Open CMD and run:

java -version

What I keep in mind while reading the output:

  • java -version typically prints to stderr, not stdout. That’s normal.
  • The output usually includes:

– A version string (for example 21.0.2)

– Build/vendor info

– The VM type (HotSpot, OpenJ9, etc.)

– 64-bit vs 32-bit clues

If you see ‘java‘ is not recognized as an internal or external command, Java may still be installed but not on PATH (or you only have an IDE-bundled runtime).

1a) Newer alternative: java --version

On Java 9+, there’s also:

java --version

I like --version because it’s concise, but if you run it on a very old Java it may fail. If I’m walking someone through checks on an unknown machine, I still start with java -version.

2) Check the compiler version: javac -version

If you develop Java, you want this to work:

javac -version

How I interpret the results:

  • If java -version works but javac -version fails, you likely have only a runtime (JRE) or your PATH points at a runtime folder.
  • If both work but show different major versions (say java is 21 but javac is 17), you may be able to compile something, but you’re in a “surprise mismatch” state. I fix that early.

3) Verify which executable Windows is launching: where java

This is the command I trust most when debugging PATH issues:

where java

where javac

Rules of thumb:

  • If you get one result, that’s what CMD will run.
  • If you get multiple results, Windows runs the first one listed.
  • If you get no results, java isn’t on PATH in that shell.

If the first path isn’t the one you expect, don’t argue with it. Fix PATH order, then re-check versions.

4) Check JAVA_HOME and PATH from CMD

JAVA_HOME is not required for Java to run, but build tools (Maven/Gradle/Ant, some IDEs) often use it.

echo %JAVA_HOME%

echo %PATH%

A common mistake is setting JAVA_HOME to the bin folder. I want it to be the JDK root.

Quick sanity check:

if exist "%JAVAHOME%\\bin\\javac.exe" (echo JDK detected) else (echo JAVAHOME is not a JDK)

5) Ask Java to print settings (best “what install is this?” clue)

When I need more than a version line, I use:

java -XshowSettings:properties -version

Look for:

  • java.home (this points to the runtime home directory)
  • java.version and java.runtime.version
  • java.vendor
  • os.arch

That java.home path is gold when you suspect PATH conflicts.

6) Confirm it’s a JDK by checking one extra tool

I like to spot-check at least one additional tool that ships with a JDK:

jar --version

jshell --version

javadoc -version

If only java works but these tools don’t exist, you’re probably looking at a runtime-only install.

PowerShell checks that reveal the real path (and can enumerate installs)

PowerShell makes it easier to inspect the exact command resolution and write repeatable diagnostics.

1) Confirm which java PowerShell resolves

In PowerShell:

Get-Command java | Format-List *

Key fields:

  • Source (full path to java.exe)
  • CommandType

If you want only the path:

(Get-Command java).Source

Do the same for javac:

(Get-Command javac).Source

If you suspect multiple hits:

Get-Command java -All | Select-Object -ExpandProperty Source

Get-Command javac -All | Select-Object -ExpandProperty Source

That -All flag is one of the fastest ways to expose “I have three JDKs and a shim.”

2) Check environment variables the PowerShell way

PowerShell reads environment variables from the current process:

$env:JAVA_HOME

$env:Path -split ‘;‘

Important Windows behavior: if you changed PATH/JAVA_HOME in the UI, existing terminals won’t automatically see it. Close and reopen the shell (sometimes a log out/in is required for all apps).

3) Print path + version together (my go-to snippet)

This makes mismatches obvious:

$java = Get-Command java -ErrorAction SilentlyContinue

if (-not $java) {

Write-Host ‘java not found on PATH‘ -ForegroundColor Yellow

exit 1

}

Write-Host "java path: $($java.Source)"

& $java.Source -version 2>&1 | ForEach-Object { "java: $_" }

$javac = Get-Command javac -ErrorAction SilentlyContinue

if ($javac) {

Write-Host "javac path: $($javac.Source)"

& $javac.Source -version 2>&1 | ForEach-Object { "javac: $_" }

} else {

Write-Host ‘javac not found (runtime-only or PATH mismatch)‘ -ForegroundColor Yellow

}

4) Find all java.exe on PATH (without scanning the whole disk)

This mirrors where java, but stays in PowerShell and is easy to extend:

$env:Path -split ‘;‘ |

Where-Object { $ -and (Test-Path $) } |

ForEach-Object { Join-Path $_ ‘java.exe‘ } |

Where-Object { Test-Path $_ } |

Get-Item |

Select-Object -ExpandProperty FullName

If you see something like C:\\Windows\\System32\\java.exe, I slow down and investigate. That’s often a stub, shim, or unexpected wrapper.

5) Scan common install directories and read the release file

When PATH is a mess, I inventory JDKs directly:

$candidates = @(

‘C:\\Program Files\\Java‘,

‘C:\\Program Files (x86)\\Java‘,

‘C:\\Program Files\\Eclipse Adoptium‘,

"$env:LOCALAPPDATA\\Programs"

)

foreach ($root in $candidates) {

if (-not (Test-Path $root)) { continue }

Get-ChildItem -Path $root -Directory -ErrorAction SilentlyContinue |

ForEach-Object {

$java = Join-Path $_.FullName ‘bin\\java.exe‘

$javac = Join-Path $_.FullName ‘bin\\javac.exe‘

$release = Join-Path $_.FullName ‘release‘

if (Test-Path $java) {

[pscustomobject]@{

Home = $_.FullName

HasJavac = (Test-Path $javac)

HasRelease = (Test-Path $release)

}

}

}

}

This isn’t perfect (vendors pick different directories), but it’s a fast, practical way to find “what’s actually installed.”

6) Registry checks (advanced, vendor-dependent)

Some Java installers register under JavaSoft keys:

$paths = @(

‘HKLM:\\SOFTWARE\\JavaSoft‘,

‘HKLM:\\SOFTWARE\\WOW6432Node\\JavaSoft‘

)

foreach ($p in $paths) {

if (Test-Path $p) {

Write-Host "Found: $p"

Get-ChildItem $p | Select-Object -ExpandProperty Name

}

}

If you see JDK or Java Runtime Environment, you can often find CurrentVersion and a JavaHome value. I treat this as a hint, not a guarantee—ZIP installs and some vendor builds won’t show up here.

UI checks when you can’t use a terminal

Sometimes you’re on a locked-down desktop, helping a teammate over a call, or you just want a quick visual check.

1) Windows Settings: Installed apps

On Windows 10/11:

  • Open SettingsAppsInstalled apps (or Apps & features)
  • Search for Java, JDK, or vendor names (like “OpenJDK”, “Temurin”, “Microsoft Build of OpenJDK”)

This tells you what Windows thinks is installed, but not which one your shell will run.

2) Control Panel: Programs and Features

  • Control Panel → ProgramsPrograms and Features

This view is great for spotting multiple side-by-side installs. If you see more than one entry, assume there are multiple java.exe candidates and validate with where java / Get-Command java.

3) The “Java” Control Panel applet (when present)

Some distributions install a Java configuration applet. If you see a Java icon in Control Panel, it usually corresponds to a specific runtime that installed it.

I treat it as a clue, not the final answer, because your builds may still use a different JDK on PATH.

4) App Execution Aliases (a sneaky Windows gotcha)

If java launches something unexpected (like redirecting you to the Microsoft Store), check:

  • SettingsAppsAdvanced app settingsApp execution aliases

Disable any conflicting alias for java.exe / javac.exe if it’s hijacking the command.

Filesystem checks: confirm what’s installed even when PATH is wrong

When java isn’t on PATH, I switch to “what folders exist?” mode.

1) Check common install locations

Typical locations:

  • C:\\Program Files\\Java\\
  • C:\\Program Files (x86)\\Java\\
  • C:\\Program Files\\Eclipse Adoptium\\
  • C:\\Users\\\\AppData\\Local\\Programs\\

A JDK root folder typically contains:

  • bin\\java.exe
  • bin\\javac.exe
  • release (metadata such as JAVA_VERSION=...)

2) Read the release file (fast, offline)

Open \\release in Notepad. You’ll typically see entries like:

  • JAVA_VERSION="21.0.x"
  • OS_NAME="Windows"
  • OSARCH="x8664"

This is one of the easiest ways to identify a folder without executing anything.

3) Run a specific java.exe by absolute path

Even with a broken PATH, you can verify a candidate install:

"%ProgramFiles%\\Java\\jdk-21\\bin\\java.exe" -version

If your JDK is in a folder without spaces (for example C:\\Java\\jdk-21), you can omit quotes.

4) JDK vs runtime sanity check

If bin\\javac.exe exists, you almost certainly have a JDK.

If it’s missing, you probably have a runtime-only install (or an incomplete/corrupted install).

Build tool and IDE checks (what your project actually uses)

Even if system Java is correct, your build might be pinned to something else.

1) Maven: mvn -v

Maven prints the Java it’s running on:

mvn -v

Look for:

  • Java version:
  • Java home:

If Maven uses a different Java than java -version, you’re likely dealing with JAVA_HOME, a toolchain, wrapper configuration, or an IDE setting.

2) Gradle: gradle -v / gradlew -v

Gradle also prints its runtime:

gradle -v

With the wrapper:

gradlew -v

Gradle may use:

  • JAVA_HOME
  • org.gradle.java.home in gradle.properties
  • Toolchains (which can download/provision a JDK)

Toolchains are great for consistency, but they can surprise you if you’re expecting “whatever is on PATH.”

3) IDE runtime vs project SDK

Modern IDEs can run on one Java while compiling with another.

What I check:

  • Project SDK / Language level (compilation target and APIs)
  • Build tool JDK (Maven/Gradle execution inside the IDE)
  • IDE runtime (Java used to run the IDE itself)

If your terminal says Java 21 but the IDE compiles with Java 17, you’ll get confusing errors (missing APIs, annotation processor quirks, module behavior differences). I align them intentionally when possible.

4) A tiny Java program to print runtime details (proof from inside the JVM)

If I want proof of what the application itself will see:

public class JavaVersionProbe {

public static void main(String[] args) {

System.out.println("java.version=" + System.getProperty("java.version"));

System.out.println("java.runtime.version=" + System.getProperty("java.runtime.version"));

System.out.println("java.vendor=" + System.getProperty("java.vendor"));

System.out.println("java.home=" + System.getProperty("java.home"));

System.out.println("os.arch=" + System.getProperty("os.arch"));

}

}

Compile and run:

javac JavaVersionProbe.java

java JavaVersionProbe

This is especially helpful for services, scheduled tasks, and GUI launchers that don’t use your interactive shell environment.

5) Environment overrides that change behavior (even if version is correct)

If Java behaves strangely (unexpected JVM args, proxies, memory flags), check:

  • JAVATOOLOPTIONS
  • JAVAOPTIONS

CMD:

echo %JAVATOOLOPTIONS%

echo %JAVAOPTIONS%

PowerShell:

$env:JAVATOOLOPTIONS

$env:JAVAOPTIONS

These don’t usually change the version string, but they can absolutely change runtime behavior enough that it feels like “a different Java.”

Traditional vs modern checks (quick recommendation table)

When I’m advising teams, I pick the method based on what you’re trying to prove.

Goal

Traditional Windows approach

Modern Windows approach

What I recommend

See Java version quickly

java -version

Get-Command java + java -version

Use both: version + path

Confirm JDK vs runtime

javac -version

PowerShell script (paths + versions)

Check javac and JAVA_HOME

Find active executable

where java

(Get-Command java).Source

Prefer PowerShell when available

Find all installs

Control Panel list

Folder + registry checks + toolchains

Start with folders, then registry

Check what build uses

mvn -v, gradle -v

Toolchains + wrapper config

Trust build tool output over systemIf you only remember one thing: a version string without the executable path is not enough evidence on Windows.

Common mistakes (and the fixes I apply first)

These are the issues I see most often when someone tells me “Java is installed, but the version is wrong.”

Mistake 1: PATH points to an older Java

Symptom:

  • You installed a newer JDK, but java -version still shows the old one.

Fix:

  • Run where java (or Get-Command java) and inspect the first path.
  • Reorder PATH so the desired JDK bin comes first.
  • Close and reopen terminals after changes.

Mistake 2: java works but javac is missing

Symptom:

  • java -version prints fine
  • javac -version fails

Fix:

  • Install a JDK (not runtime-only)
  • Point PATH at \\bin, not \\bin
  • Set JAVA_HOME to the JDK root

Mistake 3: JAVA_HOME points at bin (or points at a runtime)

Symptom:

  • Tools can’t find a compiler
  • Maven/Gradle chooses a different Java home than you expect

Fix:

  • JAVA_HOME should look like C:\\Program Files\\Java\\jdk-21 (a folder containing bin\\javac.exe)
  • PATH should include %JAVA_HOME%\\bin

Mistake 4: Different Java in services, scheduled tasks, CI agents

Symptom:

  • Works in your terminal, fails in Task Scheduler / services / CI

Why:

  • Those environments may have a different PATH, different user profile, or a hardcoded Java path.

Fix:

  • Print Java properties from inside the app (use JavaVersionProbe).
  • Check the task/service configuration for an absolute java.exe.

Mistake 5: 32-bit vs 64-bit confusion

Symptom:

  • Native integrations fail
  • You see odd library loading errors

Fix:

  • Ensure the installed Java matches your target architecture.
  • Confirm with java -version output and the install folder (usually Program Files for 64-bit, Program Files (x86) for 32-bit).

Mistake 6: java is an alias/stub, not your JDK

Symptom:

  • java opens the Microsoft Store or points to an unexpected location.

Fix:

  • Check App Execution Aliases.
  • Use where java / Get-Command java -All to find the real executable.
  • Prefer absolute paths in automation.

Mistake 7: You fixed PATH, but your terminal didn’t pick it up

Symptom:

  • You changed PATH in Windows settings, but your already-open terminal still runs the old Java.

Fix:

  • Close and reopen CMD/PowerShell.
  • If it’s still wrong, log out and back in.

My quick checklist (practical order)

If you want the shortest path to a stable setup, I do this in order:

  • where java and where javac
  • java -version and javac -version
  • echo %JAVAHOME% (or $env:JAVAHOME)
  • mvn -v or gradle -v for the project
  • If anything disagrees, fix PATH order and set JAVA_HOME to a JDK root

Managing multiple JDKs intentionally (without breaking everything)

Multiple JDKs on one Windows machine is normal. What causes pain is when switching is ad-hoc and undocumented.

1) Temporary switch for a single CMD session

If I only need Java 17 for one build, I don’t touch global PATH. I do a session-only override:

set JAVA_HOME=C:\\Java\\jdk-17

set PATH=%JAVA_HOME%\\bin;%PATH%

java -version

If your JDK path has spaces, use quotes:

set "JAVA_HOME=%ProgramFiles%\\Java\\jdk-17"

set "PATH=%JAVA_HOME%\\bin;%PATH%"

Close the terminal to revert.

2) Temporary switch for a single PowerShell session

In PowerShell:

$env:JAVA_HOME = ‘C:\\Java\\jdk-17‘

$env:Path = "$env:JAVA_HOME\\bin;$env:Path"

java -version

Close the shell to revert.

3) Deterministic builds: let the build tool pick the JDK

If you’re using Gradle toolchains or Maven toolchains, you can often stop caring about the system Java for compilation.

That’s my preferred long-term approach for teams because:

  • Developers keep a stable “default” JDK
  • The build enforces the correct JDK version
  • CI becomes more consistent

4) Use absolute paths in automation

For scheduled tasks, services, and scripts that must not break when PATH changes:

"%ProgramFiles%\\Java\\jdk-21\\bin\\java.exe" -version

A repeatable “Java sanity check” routine (copy/paste)

When I’m onboarding someone or debugging a machine, I want a quick diagnostic that answers:

  • What does this shell run for java and javac?
  • Are they the same install?
  • Is JAVA_HOME consistent?

CMD quick routine

@echo === java on PATH ===

where java

java -version 2>&1

@echo.

@echo === javac on PATH ===

where javac

javac -version 2>&1

@echo.

@echo === JAVA_HOME ===

echo %JAVA_HOME%

if defined JAVA_HOME (

if exist "%JAVAHOME%\\bin\\java.exe" (echo JAVAHOME has java.exe) else (echo JAVA_HOME missing java.exe)

if exist "%JAVAHOME%\\bin\\javac.exe" (echo JAVAHOME has javac.exe) else (echo JAVA_HOME missing javac.exe)

)

PowerShell quick routine

Write-Host "=== java resolution ==="

Get-Command java -All -ErrorAction SilentlyContinue | Select-Object Name, Source

java -version 2>&1

Write-Host "\n=== javac resolution ==="

Get-Command javac -All -ErrorAction SilentlyContinue | Select-Object Name, Source

javac -version 2>&1

Write-Host "\n=== env ==="

"JAVAHOME=$env:JAVAHOME"

"JAVATOOLOPTIONS=$env:JAVATOOLOPTIONS"

"JAVAOPTIONS=$env:JAVAOPTIONS"

Next steps for a stable setup

Once you’ve verified the versions, I like to make the machine predictable for the next six months—not just correct right now.

1) Pick a default JDK and set JAVA_HOME cleanly

I pick one “default” JDK for interactive work.

  • JAVA_HOME points to the JDK root directory (example: C:\\Program Files\\Java\\jdk-21)
  • PATH includes %JAVA_HOME%\\bin early enough that it wins

Litmus test: %JAVA_HOME%\\bin\\javac.exe exists.

2) Decide system-wide vs per-user config

Windows supports environment variables:

  • Per-user (only your login)
  • System-wide (all users, and often services)

For CI agents and shared machines, I prefer system-wide settings. For personal machines with lots of dev tools, user-level settings reduce collateral damage.

3) Don’t over-edit PATH

I aim for exactly one Java entry on PATH:

  • %JAVA_HOME%\\bin

Multiple ...\\bin entries from different JDKs is how “wrong Java on PATH” keeps coming back.

4) If you need multiple JDKs, document the switching strategy

Multiple JDKs is common for maintaining older services while developing new ones. What matters is switching is intentional:

  • Toolchains for builds (best for teams)
  • Session-only overrides for occasional switches
  • Absolute paths for automation

5) Verify from the places that matter

After you “fix Java,” verify from:

  • A fresh CMD window
  • A fresh PowerShell window
  • The project build tool (mvn -v / gradlew -v)
  • Any service/task/CI agent that runs Java

If all of those agree on both path and version, you’re in a good place.

Scroll to Top