Reputation: 15096
I wish to determine whether Java is running on Windows, and have seen many different suggestions which include various permutations of the System property os.name
with startsWith
/ indexOf
/ contains
/ toLowerCase(Locale.ENGLISH)
/ toLowerCase()
, or just File.separatorChar
.
I scanned JDK source code to see whether there was a definitive answer (see below) and a few other SO posts which suggest:
String os = System.getProperty("os.name" /**, "<Surely os.name is never null?>" */);
List<Boolean> isWindows = List.of(
os.startsWith("Windows"),
os.contains("Windows"),
os.toLowerCase().startsWith("windows"),
os.toLowerCase().contains("windows"),
os.toLowerCase(Locale.ENGLISH).contains("windows"),
os.toLowerCase(Locale.ENGLISH).startsWith("windows"),
File.separatorChar == '\\'
);
System.out.println("os.name ="+os);
System.out.println("os.name(UTF-8)="+Arrays.toString(os.getBytes(StandardCharsets.UTF_8)));
System.out.println("isWindows ="+isWindows);
Is there any permutation of OS / language installation which incorrectly identifies isWindows
using the above conditions, where true/false is inconsistent or wrong?
// For Windows I would expect all true, such as:
os.name =Windows 10
os.name(UTF-8)=[87, 105, 110, 100, 111, 119, 115, 32, 49, 48]
isWindows =[true, true, true, true, true, true, true]
// For non-Windows I would expect all false such as:
os.name =Linux
os.name(UTF-8)=[76, 105, 110, 117, 120]
isWindows =[false, false, false, false, false, false, false]
JDK source code examples
For reference, this is where isWindows
is detected in Open JDK17 source code (from a recent git fetch
NOT final release candidate):
src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java
System.getProperty("os.name").toLowerCase().startsWith("win"));
src/java.smartcardio/share/classes/sun/security/smartcardio/CardImpl.java
src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java
isWindows = System.getProperty("os.name").startsWith("Windows"))
src/java.desktop/share/classes/sun/font/FontUtilities.java
isWindows = System.getProperty("os.name", "unknownOS").startsWith("Windows");
src/java.base/share/classes/java/util/zip/ZipFile.java
src/java.desktop/share/classes/sun/awt/OSInfo.java
VM.getSavedProperty("os.name").contains("Windows")
System.getProperty("os.name").contains("Windows")
src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
boolean isWindows = osName != null && osName.contains("Windows");
src/java.desktop/share/classes/javax/swing/plaf/basic/BasicFileChooserUI.java
boolean isWin32 = (File.separatorChar == '\\')
src/jdk.jpackage/share/classes/jdk/jpackage/internal/Platform.java
Note that I've omitted this test in case of confusion with Darwin OS:
String os = System.getProperty("os.name").toLowerCase();
if (os.indexOf("win") >= 0) {
platform = Platform.WINDOWS;
}
Upvotes: 7
Views: 2914
Reputation: 15096
After noting the various comments and other posts, I've not found a reason not to continue using the isWindows
check I currently have in my code, which is simply the first test listed:
boolean isWindows = System.getProperty("os.name").startsWith("Windows");
The first six tests in my question appear to detect isWindows
correctly, but not the last item File.separatorChar == '\\'
(as that is also true on OS/2).
Note that in Turkish the lower case value of "I" is not equal to "i". Try:
"I".toLowerCase(Locale.forLanguageTag("TR")).equals("i") // char:305
"i".toUpperCase(Locale.forLanguageTag("TR")).equals("I") // char:304
Maybe this explains why some developers use .toLowerCase(Locale.ENGLISH)
but nothing changes for any of the test results unless os.name
property is uppercase in Turkish installation.
Thanks for all the suggestions.
Upvotes: 3