写点什么

Java 新技术:文字块

用户头像
范学雷
关注
发布于: 2020 年 05 月 03 日
Java新技术:文字块

聊聊Java的进展和新技术,是我给自己在InfoQ写作平台设定的一个小目标。为了方便你检索、阅读,我以“Java新技术”作为这一类的文字标题的起始。



第一篇文章,我们聊聊Java的文字块。 如果你想练练手,本文代码可以从github下载

文字块正式进入JDK

2020年4月2日,文字块提案获得了批准,正式成为JDK 15的一部分。4月15日,文字块的实现代码并入JDK 15。 你如果想要先睹为快,可以下载JDK 15的抢先体验版

什么是文字块?

文字块是一个由多行文字构成的字符串。比如,下面的textBlock字符串就是通过文字块定义的。

String textBlock = """
<!DOCTYPE html>
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
""";



为什么需要文字块?

为什么需要文字块呢? 其实,只要我们看看没有文字块的时候,应该怎么定义上面的字符串常量,我们就明白了。



如果使用普通的字符串,这样的字符串常量定义看起来像下面的样子。

String stringBlock =
"<!DOCTYPE html>\n" +
"<html>\n" +
" <body>\n" +
" <h1>Hello World!</h1>\n" +
" </body>\n" +
"</html>\n";



要定义这样的多行的字符串常量,需要插入使用很多换行符以及字符串连接符。这样的格式看起来可没有文字块养眼,而且很容易出错。特别是要从别的地方拷贝一段HTML或者SQL语句,然后转换成上面格式的字符串,是不是出力多,收效少,需要特别的耐心?遗憾的是,这样的工作还特别多,HTML, SQL, XML, JSON, HTTP, 随便就可以列一大堆。



文字块的引入,减轻了多行字符串的编码压力,提高了代码的可读性,进而使得代码更容易维护。



怎么使用文字块?

文字块使用三个双引号来界定文字内容。需要注意的是,声明起始界定符这一行,界定符后只允许空格和换行符。文字内容必须从下一行开始。下面的声明和定义是不合语法的,编译器会检查报错。

String textBlock = """<!DOCTYPE html>
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
""";



结束界定符要紧随着文字内容结束。 上面的例子中,字符串的最后一个字符是换行符。 而下面的这个例子中,字符串的最后一个字符就不是换行符了。

String textBlock = """
<!DOCTYPE html>
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>""";

由于使用了三个双引号作为界定符,文字内容可以直接使用双引号,不再需要使用转义字符

String textBlock = """
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
""";
System.out.println("The text block code:\n" + textBlock);



下面显示的上面这个例子的运行结果。从这个结果我们可以看出,输出直接显示了文字内容的格式,包括换行符。 但是,对比于代码,每一行的文字开头都被切除了八个空格。

The text block code:
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>




Java怎么处理文字块?

像普通字符串一样,文字块是字符串的一种常量表达式。不同于常规字符串的是,在编译期,文字块要顺序通过如下三个不同的编译步骤:

  1. 为了降低不同平台间换行符的表达差异,编译器把文字内容里的换行符统一转换成LF(\u000A);

  2. 删除文字内容里不必要空格,包括文字内容和结束界定符共有的前导空格或者缩进,以及所有的尾部空格;

  3. 处理转义字符。



为了说明文字块的编译处理,下面的三个例子,我们使用小数点号‘.’表示要删除的前导空格,使用叹号‘!’表示要删除的尾部空格。

// There are 8 leading white spaces in common
String textBlock = """
........<!DOCTYPE html>
........<html>
........ <body>
........ <h1>Hello World!</h1>!!!!
........ </body>
........</html>
........""";



// There are 4 leading white spaces in common
String textBlock = """
.... <!DOCTYPE html>
.... <html>
.... <body>
.... <h1>Hello World!</h1>
.... </body>
.... </html>
....""";



// There are 8 leading white spaces in common
String textBlock = """
........<!DOCTYPE html>
........<html>
........ <body>
........ <h1>Hello World!</h1>!!!!
........ </body>
........</html>
........!!!!""";



段落该怎么表达?

我们知道,编码规范一般都限定每一行的字节数 ,通常是80个或者120个字节。可是一个段落通常要超出这个限制。文字块里的换行符要保留,编码规范要遵守,该如何表达段落或者一长行呢?



文字块引入了一个新的转义字符,'\',行连接符。 比如,下面的例子中行连接符的使用,就把"Hello World!"连接在一行里了。

String textBlock = """
<!DOCTYPE html>
<html>
<body>
<h1>Hello \
World!</h1>
</body>
</html>
""";



连接后的字符,是”HelloWorld“还是”Hello World“?两个单词之间还有空格吗?还记得我们前面说过的编译器处理顺序吗?空格处理先于转义字符处理。因此,行连接符前的空格不算尾部空格,因此会得到保留。

尾部空格可以回来吗?

文字块里的尾部空格在编译期会被删除。 一般情况下,尾部空格没有什么实质性的作用。但是,万一需要尾部空格,它们还可以回来吗?文字块还引入了另外一个新的转义字符,'\s',空格转义符。空格转义符表示一个空格。由于我们前面说过的文字块的编译器处理顺序,空格转义符之前的空格也被保留。



比如下面的例子中,字符串的前两行就包含尾部空格。

// There are 8 leading white spaces in common
String textBlock = """
........<!DOCTYPE html> \s!!!!
........<html> \s
........ <body>!!!!!!!!!!
........ <h1>Hello World!</h1>
........ </body>
........</html>
........!!!!""";



文字块是字符串

需要注意的是,文字块定义的是字符串。既然是字符串,就可以使用字符串的API和对应的操作。



比如,普通字符串和文字块可以混合使用:

String printedHtml = "The HTML code looks like:\n" +
"""
<!DOCTYPE html>
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
""";



比如,调用String的方法:

int size = """
<!DOCTYPE html>
<html>
<body>
<h1>Hello \
World!</h1>
</body>
</html>
""".length();



或者,使用嵌入式表达式:

String textBlock = """
<!DOCTYPE html>
<html>
<body>
<h1>%s</h1>
</body>
</html>
""".formatted("Hello World!");



最后,一定要理解下面两点:

  • 文字块是在编译器处理的一种字符串常量表达式

  • 文字块的处理要顺序通过三个编译步骤。



理解了上面两点,文字块的很多概念就清楚了,用法也就清楚了。



好的,今天我们就聊到这儿。

发布于: 2020 年 05 月 03 日阅读数: 433
用户头像

范学雷

关注

因为慢,所以快。 2018.04.29 加入

制订和维护Java安全规范。

评论

发布
暂无评论
Java新技术:文字块