181

I need to work around a Java bug in JDK 1.5 which was fixed in 1.6. I'm using the following condition:

if (System.getProperty("java.version").startsWith("1.5.")) {
    ...
} else {
    ...
}

Will this work for other JVMs? Is there a better way to check this?

Boann
  • 48,794
  • 16
  • 117
  • 146
list
  • 1,813
  • 2
  • 12
  • 4

14 Answers14

159

java.version is a system property that exists in every JVM. There are two possible formats for it:

  • Java 8 or lower: 1.6.0_23, 1.7.0, 1.7.0_80, 1.8.0_211
  • Java 9 or higher: 9.0.1, 11.0.4, 12, 12.0.1

Here is a trick to extract the major version: If it is a 1.x.y_z version string, extract the character at index 2 of the string. If it is a x.y.z version string, cut the string to its first dot character, if one exists.

private static int getVersion() {
    String version = System.getProperty("java.version");
    if(version.startsWith("1.")) {
        version = version.substring(2, 3);
    } else {
        int dot = version.indexOf(".");
        if(dot != -1) { version = version.substring(0, dot); }
    } return Integer.parseInt(version);
}

Now you can check the version much more comfortably:

if(getVersion() < 6) {
    // ...
}
MultiplyByZer0
  • 6,302
  • 3
  • 32
  • 48
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • 7
    It is ok for 1.5 but 1.6 is not precise as a floating point number. – Ha. Apr 07 '10 at 10:08
  • 1
    FP precision aside, for the OP's needs the code provided should at least be (version > 1.5), not >=. To the OP: if you use your current String comparison do you need to check below 1.5 too? – Steven Mackenzie Apr 07 '10 at 10:58
  • 1
    @Ha: Maybe but `double version = 1.6` and `Double.parseDouble("1.6")` should still yield the same bit pattern, right? Since we don't do arithmetics on the number (only a simple compare), even == will work as expected. – Aaron Digulla Apr 07 '10 at 12:54
  • This code results in `java.lang.NumberFormatException: multiple points`. Instead you want `getVersion` to return the double substring of `version.substring(0, pos - 1)`. (Otherwise you're trying to create a double out of the string "1.7.0" which is not a proper double). – ChaimKut Dec 05 '14 at 12:19
  • @ChaimKut: Thanks, fixed. Since the first part of the number is always 1, I'm wondering if it doesn't make sense to skip that and instead return minor version + patch level. – Aaron Digulla Dec 05 '14 at 13:30
  • 1
    but soon we will have version 1.1 again... or maybe instead of 1.10 we start with 2.0 [:-) – user85421 Aug 04 '16 at 11:27
  • 10
    In Java 9, there won't be "1." in front. The string will start with "9..." – Dave C Nov 21 '16 at 18:26
  • Within a groovy script, `java.version` is not accessible. However, `System.getProperty("java.version")` did work! (On a side node, your conversion to fails in my case, where the version string is `1.8.0_151`) – Martin Rüegg Nov 16 '17 at 10:12
  • @MartinRüegg Try to debug your code. My code simply looks for the second `.` (dot) in the string and parses that as double. That should try to parse `"1.8"`. What's your locale? What's your decimal separator character? I thought `Double.parseDouble()` isn't dependent on the locale but maybe they fixed/changed that. – Aaron Digulla Nov 28 '17 at 12:58
  • @AaronDigulla, you're right. I don't know what went wrong the other day. Just tried it again and works perfectly fine! Thanks. – Martin Rüegg Dec 06 '17 at 11:00
  • In leetcode REPL environment i am getting following exception when trying to run this code: java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.version" "read") – Tarun Dec 08 '20 at 01:59
  • 1
    @Tarun They probably have a `SecurityManager` installed. Check the documentation how to access system properties in leetcode REPL. – Aaron Digulla Dec 16 '20 at 15:07
64

What about getting the version from the package meta infos:

String version = Runtime.class.getPackage().getImplementationVersion();

Prints out something like:

1.7.0_13

Stefan
  • 12,108
  • 5
  • 47
  • 66
63

Runtime.version()

Since Java 9, you can use Runtime.version(), which returns a Runtime.Version:

Runtime.Version version = Runtime.version();
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
43

These articles seem to suggest that checking for 1.5 or 1.6 prefix should work, as it follows proper version naming convention.

Sun Technical Articles

Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • 1
    Is there a way to obtain whether it's Oracle or Open? – Joe C Oct 20 '19 at 00:37
  • 2
    Now that the versioning syntax has changed beginning in Java 9, the other answers are more useful. – ReinstateMonica3167040 Sep 18 '21 at 16:16
  • To address @JoeC question some years later: look at some of the other system properties, in particular these six: `java.runtime.name`, `java.vendor`, `java.vm.{name,vendor}`, `java.vm.specification.{name,vendor}` I believe the first two may be semi-standardized by the official JVM/JLS spec, and the rest may be sort of standard conventions by now. Depending on what exactly the use case is in the application, often one or more of those properties can be the deciding factor. – Ti Strga Aug 15 '23 at 16:36
33

The simplest way (java.specification.version):

double version = Double.parseDouble(System.getProperty("java.specification.version"));

if (version == 1.5) {
    // 1.5 specific code
} else {
    // ...
}

or something like (java.version):

String[] javaVersionElements = System.getProperty("java.version").split("\\.");

int major = Integer.parseInt(javaVersionElements[1]);

if (major == 5) {
    // 1.5 specific code
} else {
    // ...
}

or if you want to break it all up (java.runtime.version):

String discard, major, minor, update, build;

String[] javaVersionElements = System.getProperty("java.runtime.version").split("\\.|_|-b");

discard = javaVersionElements[0];
major   = javaVersionElements[1];
minor   = javaVersionElements[2];
update  = javaVersionElements[3];
build   = javaVersionElements[4];
ɲeuroburɳ
  • 6,990
  • 3
  • 24
  • 22
mvanle
  • 1,847
  • 23
  • 19
12

Example for Apache Commons Lang:

import org.apache.commons.lang.SystemUtils;

    Float version = SystemUtils.JAVA_VERSION_FLOAT;

    if (version < 1.4f) { 
        // legacy
    } else if (SystemUtils.IS_JAVA_1_5) {
        // 1.5 specific code
    } else if (SystemUtils.isJavaVersionAtLeast(1.6f)) {
        // 1.6 compatible code
    } else {
        // dodgy clause to catch 1.4 :)
    }
mvanle
  • 1,847
  • 23
  • 19
  • 1
    `version < 1.4f`... What happens when `version = 1.4f`? – ADTC Jul 04 '14 at 08:05
  • Ah yes, you are right - 1.4f would not be captured in the above example. The example is only demonstrating Apache Commons Lang's constants as an alternative to Java's properties :) – mvanle Sep 03 '14 at 02:52
  • You can edit the answer and change it to `version <= 1.4f`.. Unfortunately `SystemUtils` does not provide a `isJavaVersionLessThan` method but then (fortunately) you could also put the legacy code in an `else` block, which is cleaner. – ADTC Sep 03 '14 at 03:06
  • Err... *"dodgy clause to catch 1.4"*? Shouldn't `1.4f` fall back to legacy code? – ADTC Sep 03 '14 at 03:28
  • 2
    I would suggest: `if (SystemUtils.IS_JAVA_1_5) { /* 1.5 specific code */ } else if (SystemUtils.isJavaVersionAtLeast(1.6f)) { /* modern code */ } else { /* fall back to legacy code */ }`. Specific code above, generic code below, fallback code at the very bottom. – ADTC Sep 03 '14 at 03:30
  • @ADTC: You are right. Your structure is better than mine. But the reason I want to keep my structure is because people can see that `SystemUtils.JAVA_VERSION_FLOAT` can and/or must be compared with a float literal. That's my only excuse :) – mvanle Nov 07 '14 at 17:44
11

Just a note that in Java 9 and above, the naming convention is different. System.getProperty("java.version") returns "9" rather than "1.9".

Sina Madani
  • 1,246
  • 3
  • 15
  • 27
8

Does not work, need --pos to evaluate double:

    String version = System.getProperty("java.version");
    System.out.println("version:" + version);
    int pos = 0, count = 0;
    for (; pos < version.length() && count < 2; pos++) {
        if (version.charAt(pos) == '.') {
            count++;
        }
    }

    --pos; //EVALUATE double

    double dversion = Double.parseDouble(version.substring(0, pos));
    System.out.println("dversion:" + dversion);
    return dversion;
}
Bruno Vieira
  • 3,884
  • 1
  • 23
  • 35
Alessandro
  • 89
  • 1
  • 1
7

Here's the implementation in JOSM:

/**
 * Returns the Java version as an int value.
 * @return the Java version as an int value (8, 9, etc.)
 * @since 12130
 */
public static int getJavaVersion() {
    String version = System.getProperty("java.version");
    if (version.startsWith("1.")) {
        version = version.substring(2);
    }
    // Allow these formats:
    // 1.8.0_72-ea
    // 9-ea
    // 9
    // 9.0.1
    int dotPos = version.indexOf('.');
    int dashPos = version.indexOf('-');
    return Integer.parseInt(version.substring(0,
            dotPos > -1 ? dotPos : dashPos > -1 ? dashPos : 1));
}
simon04
  • 3,054
  • 29
  • 25
6

If you can have dependency to apache utils you can use org.apache.commons.lang3.SystemUtils.

    System.out.println("Is Java version at least 1.8: " + SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_8));
P.Kurek
  • 71
  • 1
  • 4
3

Don't know another way of checking this, but this: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#getProperties()" implies "java.version" is a standard system property so I'd expect it to work with other JVMs.

Tom Jefferys
  • 13,090
  • 2
  • 35
  • 36
1

Here is the answer from @mvanle, converted to Scala: scala> val Array(javaVerPrefix, javaVerMajor, javaVerMinor, _, _) = System.getProperty("java.runtime.version").split("\\.|_|-b") javaVerPrefix: String = 1 javaVerMajor: String = 8 javaVerMinor: String = 0

Mike Slinn
  • 7,705
  • 5
  • 51
  • 85
0

https://docs.oracle.com/javase/9/docs/api/java/lang/Runtime.Version.html#version--

 Runtime.version().version()

For 17.0.1 it returns [17, 0, 1] One can use Runtime.version().version().get(0) to get the major java version.

sch
  • 21
  • 5
-1

In kotlin:

/**
 * Returns the major JVM version, e.g. 6 for Java 1.6, 8 for Java 8, 11 for Java 11 etc.
 */
public val jvmVersion: Int get() = System.getProperty("java.version").parseJvmVersion()

/**
 * Returns the major JVM version, 1 for 1.1, 2 for 1.2, 3 for 1.3, 4 for 1.4, 5
 * for 1.5 etc.
 */
fun String.parseJvmVersion(): Int {
    val version: String = removePrefix("1.").takeWhile { it.isDigit() }
    return version.toInt()
}
Martin Vysny
  • 3,088
  • 28
  • 39