Setting Java VM line.separator
Has anybody found a way how to s开发者_Python百科pecify the Java line.separator
property on VM startup? I was thinking of something like this:
java -Dline.separator="\n"
But this doesn't interprete the "\n" as linefeed character. Any ideas?
Try using java -Dline.separator=$'\n'
. That should do the trick, at least in bash.
Here is a test-run:
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$
Note:
The expression $''
uses the Bash feature ANSI-C Quoting. It expands backslash-escaped characters, thus $'\n'
produces a line feed (ASCII code 10) character, enclosed in single quotes. See Bash manual, section 3.1.2.4 ANSI-C Quoting.
To bridge the gap between aioobe and Bozho's answers, I also would advise against setting the line.separator
parameter at JVM startup, as this potentially breaks many fundamental assumptions the JVM and library code makes about the environment being run in. For instance, if a library you depend on relies on line.separator
in order to store a config file in a cross-platform way, you've just broken that behavior. Yes, it's an edge case, but that makes it all the more nefarious when, years from now, a problem does crop up, and now all your code is dependent on this tweak being in place, while your libraries are (correctly) assuming it isn't.
That said, sometimes these things are out of your control, like when a library relies on line.separator
and provides no way for you to override that behavior explicitly. In such a case, you're stuck overriding the value, or something more painful like re-implementing or patching the code manually.
For those limited cases, the it's acceptable to override line.separator
, but we've got to follow two rules:
- Minimize the scope of the override
- Revert the override no matter what
Both of these requirements are well served by AutoCloseable
and the try-with-resources syntax, so I've implemented a PropertiesModifier
class that cleanly provides both.
/**
* 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<String, String> 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<String, String> 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);
}
}
My use case was with Files.write()
, which is a very convenient method, except it explicitly relies on line.separator
. By wrapping the call to Files.write()
I can cleanly specify the line separator I want to use, without risking exposing this to any other parts of my application (take note of course, that this still isn't thread-safe).
try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) {
Files.write(file, ImmutableList.of(line), Charsets.UTF_8);
}
I wouldn't do that if I were you. The line-separator is platform specific, and should remain so. If you want to write windows-only or linux-only files, define a UNIX_LINE_SEPARATOR
constant somewhere and use it instead.
精彩评论