写在前面
文字块(text blocks)这个特性,首先在 JDK 13 中以预览版的形式发布。在 JDK 14 中,改进的文字块再次以预览版的形式发布。最后,文字块在 JDK 15 正式发布。
在没有使用文字块之前,我们项目中也许有这样的一串代码:
String htmlString =
"<!DOCTYPE html>\n" +
"<html>\n" +
" <body>\n" +
" <h1>\"Hello World!\"</h1>\n" +
" </body>\n" +
"</html>\n";
System.out.println(htmlString);
使用String的加号来拼接HTML, SQL, XML, JSON,似乎是对长文本唯一的处理方式,令人繁琐的引号和加号,可读性差不说,写起来也很麻烦。
一、文字块的使用
在JDK15版本以后,我们就可以正式使用文字块了,我们对上面代码加以优化:
String htmlString = """
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
""";
System.out.println(htmlString);
以上代码是不是清晰多了?
使用三个双引号引起来的文本,就是我们所说的文字块语法了,也就是“所见即所得”,不再有特殊字符了。
二、文字块的语法注意点
1、开始分隔符单独成行
文字块由零个或多个内容字符组成,从开始分隔符开始,到结束分隔符结束。
开始分隔符是由三个双引号字符 (“”“) ,后面跟着的零个或多个空格,以及行结束符组成的序列。
结束分隔符是一个由三个双引号字符 (”“”) 组成的序列。
注意!
开始分隔符必须单独成行
;三个双引号字符后面的空格和换行符都属于开始分隔符,也就是说,三个双引号的下一行,才算文本正式开始。
结束分隔符只有一个由三个双引号字符组成的序列。结束分隔符之前的字符,包括换行符,都属于文字块的有效内容。
// 编译错误,开始分隔符未单独成行
String htmlString = """ """;
// 编译错误,开始分隔符未单独成行
String htmlString = """ asd
<!DOCTYPE html>
</html>""";
// 正确语法
String htmlString = """
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
""";
2、可以正常调用String的API
文字块就是字符串。既然是字符串,就能够使用字符串支持的各种 API 和操作方法。
String htmlString = """
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>""";
System.out.println(htmlString.length());
htmlString.equals(testString);
String s = htmlString.toLowerCase();
System.out.println(htmlString);
System.out.println("Here is the text block:\n" +
"""
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
""");
// 使用String的嵌入式表达式
String htmlString = """
<!DOCTYPE html>
<html>
<body>
<h1>%s</h1>
</body>
</html>
""".formatted("Hello World!");
当然也可以使用字符串的\n 换行等转义符。
3、首行自动缩进
public static void main(String[] args) {
String htmlString = """
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>""";
System.out.println(htmlString);
}
以上代码的运行结果:
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
我们发现,并不会带着前面的一大长串空格,而是整体缩进了。
Java 文本块会删除所有附带的缩进,只保留必要的缩进。Java 编译器也会去除文本块中每一行上的尾随空格
原因是不同于传统字符串的是,在编译期,文字块要顺序通过如下三个不同的编译步骤:
1.为了降低不同平台间换行符的表达差异,编译器把文字内容里的换行符统一转换成 LF(\u000A);
2.为了能够处理 Java 源代码里的缩进空格,要删除所有文字内容行和结束分隔符共享的前导空格,以及所有文字内容行的尾部空格;
3.最后处理转义字符,这样开发人员编写的转义序列就不会在第一步和第二步被修改或删除。
按需缩进
我们将上面代码稍微修改一下,将结尾的三个双引号换行并往前缩进:
public static void main(String[] args) {
String htmlString = """
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
""";
System.out.println(htmlString);
}
我们会发现执行结果就是结尾的三个双引号缩进的位置开始的:
<!DOCTYPE html>
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
找回尾部空格
编译器会自动忽略尾部的空格,我们确实想要尾部空格怎么办?
文字块引入了另外一个新的转义字符,‘\s’,空格转义符。
以下代码会携带者我们的尾部空格进行输出:
public static void main(String[] args) {
String htmlString = """
<!DOCTYPE html> \s
<html>
<body>
<h1>"Hello World!"</h1>
</body>
</html>
""";
System.out.println(htmlString);
}
4、隐式换行符处理长段落
当我们一行比较长时,可以使用 \ 来换行
String htmlString = """
<!DOCTYPE html>
<html>
<body>
<h1>"Hello \
World!"</h1>
</body>
</html>
""";
System.out.println(htmlString);
三、总结
1.仅当文本块可以提高代码的清晰度时才使用文本块,特别是对于多行字符串。
2.如果字符串适合用例,则始终首选使用字符串。它们更有利于应用程序性能。
3.要保持所需的缩进,请始终使用相对于内容上最后一行的位置关闭三重引号的位置。
4.避免在复杂表达式(如 lambda 表达式或流操作)中使用内联文本块,以保持可读性。考虑重构为局部变量或静态最终字段。
5.仅使用空格或仅使用制表符来缩进文本块。混合空格将导致不规则缩进的结果。
参考资料
极客时间《深入剖析 Java 新特性》
Java – 文本块和最佳实践
jdk官方文档