164

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
  • 47,128
  • 13
  • 114
  • 141
list
  • 1,643
  • 2
  • 11
  • 4

13 Answers13

140

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
  • 5,209
  • 3
  • 29
  • 46
Aaron Digulla
  • 310,263
  • 103
  • 579
  • 794
  • 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
  • 9
    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
63

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
  • 11,867
  • 5
  • 44
  • 63
50

Runtime.version()

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

Runtime.Version version = Runtime.version();
Basil Bourque
  • 262,936
  • 84
  • 758
  • 1,028
Eng.Fouad
  • 111,301
  • 67
  • 311
  • 403
  • 1
    echo "System.err.print(Runtime.version().major())" | $JDK/bin/jshell 2>&1 > /dev/null – judovana Feb 27 '18 at 10:04
  • 4
    @judovana Runtime.version().major() is deprecated since Java10, the equivalent is now Runtime.version().feature(). – fidekild Oct 22 '20 at 14:59
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
  • 364,035
  • 124
  • 554
  • 617
32

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,854
  • 3
  • 22
  • 22
mvanle
  • 1,613
  • 19
  • 18
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,159
  • 2
  • 13
  • 27
10

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,613
  • 19
  • 18
  • 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
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,854
  • 1
  • 22
  • 35
Alessandro
  • 89
  • 1
  • 1
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
6

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
  • 2,708
  • 26
  • 25
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
  • 12,995
  • 2
  • 34
  • 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
  • 6,972
  • 5
  • 43
  • 76
0

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
  • 2,656
  • 26
  • 33