设置Java VM line.separator

有没有人找到一种方法如何在VM启动时指定Java line.separator属性? 我在考虑这样的事情:

 java -Dline.separator="\n" 

但这并没有将“\ n”解释为换行符。 有任何想法吗?

尝试使用java -Dline.separator=$'\n' 。 应该这样做,至少在bash中。

这是一个测试运行:

 aioobe@r60:~/tmp$ cat Test.java public class Test { public static void main(String[] args) { System.out.println("\"" + System.getProperty("line.separator") + "\""); } } aioobe@r60:~/tmp$ javac Test.java && java -Dline.separator=$'\n' Test " " aioobe@r60:~/tmp$ 

注意:

表达式$''使用BashfunctionANSI-C Quoting 。 它扩展了反斜杠转义字符,因此$'\n'生成一个换行符(ASCII代码10)字符,用单引号括起来。 请参阅Bash手册,第3.1.2.4节ANSI-C报价 。

为了弥合aioobe和Bozho的答案之间的差距,我还建议不要在JVM启动时设置line.separator参数,因为这可能会破坏JVM和库代码对运行环境的许多基本假设。例如,如果a你依赖的库依赖于line.separator ,以便以跨平台的方式存储配置文件,你刚刚打破了这种行为。 是的,这是一个边缘情况,但这使得它变得更加邪恶,从现在开始,问题突然出现,现在所有的代码都依赖于这个调整,而你的库(正确地)假设它不是。

也就是说,有时这些东西是你无法控制的,比如当一个库依赖于line.separator并且没有办法让你明确地覆盖那个行为时。 在这种情况下,你会被压倒一切,或者像手动重新实现或修补代码那样更痛苦。

对于那些有限的情况,覆盖line.separator是可以接受的,但我们必须遵循两条规则:

  1. 最小化覆盖范围
  2. 无论如何都要恢复覆盖

AutoCloseable和try-with-resources语法很好地满足了这两个要求,因此我实现了一个干净地提供这两者的PropertiesModifier类。

 /** * Class which enables temporary modifications to the System properties, * via an AutoCloseable. Wrap the behavior that needs your modification * in a try-with-resources block in order to have your properties * apply only to code within that block. Generally, alternatives * such as explicitly passing in the value you need, rather than pulling * it from System.getProperties(), should be preferred to using this class. */ public class PropertiesModifier implements AutoCloseable { private final String original; public PropertiesModifier(String key, String value) { this(ImmutableMap.of(key, value)); } public PropertiesModifier(Map map) { StringWriter sw = new StringWriter(); try { System.getProperties().store(sw, ""); } catch (IOException e) { throw new AssertionError("Impossible with StringWriter", e); } original = sw.toString(); for(Map.Entry e : map.entrySet()) { System.setProperty(e.getKey(), e.getValue()); } } @Override public void close() { Properties set = new Properties(); try { set.load(new StringReader(original)); } catch (IOException e) { throw new AssertionError("Impossible with StringWriter", e); } System.setProperties(set); } } 

我的用例是Files.write() ,这是一个非常方便的方法,除了它显式依赖于line.separator 。 通过将调用包装到Files.write()我可以干净地指定我想要使用的行分隔符,而不会冒险将其暴露给我的应用程序的任何其他部分(请注意,这仍然不是线程安全的)。

 try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) { Files.write(file, ImmutableList.of(line), Charsets.UTF_8); } 

如果我是你,我不会这样做。 行分隔符是特定于平台的,应保持不变。 如果要编写仅限Windows或仅使用Linux的文件,请在某处定义UNIX_LINE_SEPARATOR常量并使用它。