首页 > 代码库 > java解惑之字符之谜(谜题16)

java解惑之字符之谜(谜题16)

谜题16:行打印程序

行分隔符是为分割文本行的字符或字符串而起的名字,并且在不同平台上它是存在差异的。在windows平台上,它由CR字符(回车)和紧随其后的LR(换行)字符组成。在UNIX平台上,通常引用单独的LF字符作为换行字符。那么,这次的谜题也就由行分隔符引出,来看看下面这个将LF字符传递给println方法的程序会打印什么,它的行为是否依赖于平台?

public class LinePrinter{
public static void main(String[] args){
//Note:\u000A is Unicode representation of linefeed(LF)
char c = 0x000A;
System.out.println(c);
}
}


其实这个程序的行为是平台无关的:它在任何平台上都不能通过编译。如果你尝试着去编译它,就会得到类似下面的出错信息:

LinePrinter.java:3:';' expected
//Note:\u000A is Unicode representation of lintfeed(LF)
1 error


看到这个或许大家都会感到熟悉,没错,这正是和谜题15犯了一样的错,在第三行注释中,\u000A是一个Unicode转义字符,谜题15中已经介绍了Unicode转义字符,不清楚的可以去看看谜题15,那么在编译器丢弃注释之前,这个Unicode转义字符就会适时的被转义为一个行分隔符,也就是说,转义后将要编译的代码是这样:

public class LinePrinter{
public static void main(String[] args){
//Note:
is Unicode representation of linefeed(LF)
char c = 0x000A;
System.out.println(c);
}
}


很显然这样的代码是不能通过编译的,修正程序最简单的方法就是在注释中移除Unicode转义字符,但这样做或许会让程序阅读者对代码要表达的内容感到迷惑,所以更好的方法是将行分隔符直接用一个转义字符序列而不是用一个十六进制整型字面常量来初始化,这样就能清楚的表达程序的内容了,从而也就不需要多余的注释了。

public class LinePrinter{
public static void main(String[] args){
char c = '\n';
System.out.println(c);
}
}


只要这么做了,程序就能确保编译通过并运行,但是这仍是一个有问题的程序,之前未修正的程序的行为(即出现编译错误)是与平台无关的,那么修正后的程序出现的行为是与平台有关的,原因也正是本谜题所要提醒的。在某些平台上,例如UNIX,它将打印两个完整的行分隔符;但是在其它平台上,例如Windows,它就不会产生这样的行为。尽管这些输出用肉眼看是一样的,但是如果它们被存储到文件中,或是输出到后续的其他处理程序中,就容易引发问题了。如果是想要打印两行空行,就应该老老实实的调用两次println方法。如果恰好使用的是JDK 5.0,那么你还可以使用格式化字符串"%n%n"的printf来代替println。%n的每一次出现都讲导致printf打印一个恰当的、与平台相关的行分隔符。

通过谜题14、谜题15以及本谜题,我们都能清楚的认识到Unicode转义字符绝对会产生混乱。所以,我们除非在确实是必需的情况下,否则就不要使用Unicode转义字符。

java解惑之字符之谜(谜题16)