如何在 JDK 中找到完整的平台相关陷阱列表,例如时区、编码、行尾等?

How can I find complete list of platform-dependent traps in JDK like timezone, encoding, line endings etc.?

我们总是希望我们的 dev/test 环境像生产环境一样,但我们经常会陷入使用 JDK 函数的陷阱,这些函数不会非常明确地暴露环境依赖性(比如所需的方法参数) 或者可以微妙地检测和注意。例如:

其中一些可以由 JVM 参数驱动,例如 -Dfile.encoding=UTF-8

但是如何找到所有这些问题呢?

陷阱的类型取决于您的应用程序类型。

要获得几乎完整的列表,您可以 运行 此检查,其中列出了您的操作系统环境变量和 java 系统属性:

import java.awt.GraphicsEnvironment;
import java.util.Map;
import java.util.Properties;

public class Sof39189179 {

    public static void main(String[] args) {

        Map<String, String> sysenv = System.getenv();

        for(String key: sysenv.keySet())
            System.out.println( key +  ": " + sysenv.get(key));

        Properties properties = System.getProperties();

        for(Object key: properties.keySet())
            System.out.println(key + ": " + properties.get(key));

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
        System.out.println("headless: " + ge.isHeadless());
    }
}

在我的电脑上,我得到以下输出(我省略了一些行):

M2: $M2_HOME/bin
JAVA_HOME: /opt/local/jdk-1.8.0_51
LANG: en_US.UTF-8
CATALINA_HOME: /opt/local/tomcat-8.0.24

...

---------------------
java.runtime.name: Java(TM) SE Runtime Environment
sun.boot.library.path: /opt/local/jdk-1.8.0_51/jre/lib/amd64
java.vm.version: 25.51-b03
java.vm.vendor: Oracle Corporation
java.vendor.url: http://java.oracle.com/
path.separator: :
java.vm.name: Java HotSpot(TM) 64-Bit Server VM
file.encoding.pkg: sun.io
user.country: US
sun.java.launcher: SUN_STANDARD
sun.os.patch.level: unknown
java.vm.specification.name: Java Virtual Machine Specification
user.dir: /home/rudolf/workspace/neon/sof39189179
java.runtime.version: 1.8.0_51-b16
java.awt.graphicsenv: sun.awt.X11GraphicsEnvironment
java.endorsed.dirs: /opt/local/jdk-1.8.0_51/jre/lib/endorsed
os.arch: amd64
java.io.tmpdir: /tmp
line.separator: 

java.vm.specification.vendor: Oracle Corporation
os.name: Linux
...

java.awt.printerjob: sun.print.PSPrinterJob
file.encoding: UTF-8
java.specification.version: 1.8
java.class.path: /home/rudolf/workspace/neon/sof39189179/bin
user.name: rudolf
java.vm.specification.version: 1.8
java.home: /opt/local/jdk-1.8.0_51/jre
sun.arch.data.model: 64
user.language: en
java.specification.vendor: Oracle Corporation
awt.toolkit: sun.awt.X11.XToolkit
java.vm.info: mixed mode
java.version: 1.8.0_51
java.ext.dirs: /opt/local/jdk-1.8.0_51/jre/lib/ext:/usr/java/packages/lib/ext
sun.boot.class.path: /opt/local/jdk-1.8.0_51/jre/lib/resources.jar:/opt/local/jdk-1.8.0_51/jre/lib/rt.jar:/opt/local/jdk-1.8.0_51/jre/lib/sunrsasign.jar:/opt/local/jdk-1.8.0_51/jre/lib/jsse.jar:/opt/local/jdk-1.8.0_51/jre/lib/jce.jar:/opt/local/jdk-1.8.0_51/jre/lib/charsets.jar:/opt/local/jdk-1.8.0_51/jre/lib/jfr.jar:/opt/local/jdk-1.8.0_51/jre/classes
java.vendor: Oracle Corporation
file.separator: /
java.vendor.url.bug: http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding: UnicodeLittle
sun.cpu.endian: little
sun.cpu.isalist: 
headless: false

您可以从此列表中确定哪些属性与您的案例相关,并检查您的代码。或者,更好的是,在编写代码时考虑到这些属性。

System.out.printf("%n") uses platform line endings

我更喜欢使用上面列出的属性,即为了打印换行符,我使用类似的东西:

String newline = (String) System.getProperties().get("line.separator");
System.out.println("newline: " +  newline);

不是您问题的直接答案,但 -XX:+PrintFlagsFinal and -XshowSettings:all 对比较不同环境有很大帮助。这些标志将显示默认(hardware/os 依赖)jvm 设置和 env/system 属性。

您还需要比较 os 设置,例如环境变量、os limits/quotas、安全设置、文件系统设置等

由于您要求完整列表:每次与操作系统或本机库交互时。

每次你不做纯计算让我们忽略严格的数学可能会有差异。有时它们很小,只出现在边缘情况下,有时它们明确地属于 API.

  • 开始新话题?受 OS 限制。
  • 想要以纳秒级精度安排任务?以平台上可用的计时器精度为准。
  • 文件名?取决于文件系统支持什么。
  • 打开套接字?可用端口范围由 OS.
  • 配置
  • ...

一般建议:阅读您正在使用的 API 的文档,了解支撑它们的 OS 功能