Java文本块
1.绪论
在之前的教程中,我们看到了如何在任何Java版本中使用多行字符串。
在本教程中,我们将详细了解如何使用Java 15的文本块功能以最有效的方式声明多行字符串。
2.使用情况
从Java 15开始,文本块可以作为一个标准功能使用。对于Java 13和14,我们需要把它作为一个预视功能启用。
文本块以“””(三个双引号)开始,后面是可选的空白和换行。最简单的例子看起来是这样的:
String example = """
Example text""";
请注意,文本块的结果类型仍然是String。文本块只是为我们提供了另一种在源代码中书写String字面的方法。
在文本块中,我们可以自由使用换行符和引号,而不需要转义换行符。它允许我们以一种更优雅和可读的方式包含HTML、JSON、SQL或任何我们需要的文字片段。
在产生的字符串中,(基础)缩进和第一个换行不包括在内。我们将在下一节中看看缩进的处理方法。
3.缩进
幸运的是,在使用文本块时,我们仍然可以正确缩进我们的代码。为了实现这一点,一部分缩进被视为源代码,而另一部分缩进被视为文本块的一部分。为了做到这一点,编译器会检查所有非空行的最小缩进。接下来,编译器会将完整的文本块向左移动。
考虑到一个包含一些HTML的文本块:
public String getBlockOfHtml() {
return """
<html>
<body>
<span>example text</span>
</body>
</html>""";
}
在这种情况下,最小缩进是12个空格。因此,<html>左边的所有12个空格以及所有后续的行都被删除。让我们来测试一下:
@Test
void givenAnOldStyleMultilineString_whenComparing_thenEqualsTextBlock() {
String expected = "<html>\n"
+ "\n"
+ " <body>\n"
+ " <span>example text</span>\n"
+ " </body>\n"
+ "</html>";
assertThat(subject.getBlockOfHtml()).isEqualTo(expected);
}
@Test
void givenAnOldStyleString_whenComparing_thenEqualsTextBlock() {
String expected = "<html>\n\n <body>\n <span>example text</span>\n </body>\n</html>";
assertThat(subject.getBlockOfHtml())
.isEqualTo(expected);
}
当我们需要明确的缩进时,我们可以对非空行(或最后一行)使用较少的缩进:
public String getNonStandardIndent() {
return """
Indent
""";
}
@Test
void givenAnIndentedString_thenMatchesIndentedOldStyle() {
assertThat(subject.getNonStandardIndent())
.isEqualTo(" Indent\n");
}
此外,我们还可以在文本块内使用转义,我们将在下一节中看到。
4.转义
4.1.转移双引号
在文本块内,双引号不必被转义。我们甚至可以通过转义其中的一个,在我们的文本块中再次使用三个双引号:
public String getTextWithEscapes() {
return """
"fun" with
whitespace
and other escapes \"""
""";
}
这是唯一必须转义双引号的情况。在其他情况下,这被认为是一种不好的做法。
4.2.转义行终止符
一般来说,换行符不必在文本块内转义。
然而,请注意,即使一个源文件有Windows行尾(\r\n),文本块也只会以换行(\n)结束。如果我们需要回车(\r)出现,我们必须明确地将其添加到文本块中:
public String getTextWithCarriageReturns() {
return """
separated with\r
carriage returns""";
}
@Test
void givenATextWithCarriageReturns_thenItContainsBoth() {
assertThat(subject.getTextWithCarriageReturns())
.isEqualTo("separated with\r\ncarriage returns");
}
有时,我们的源代码中可能会有长长的几行文字,我们希望以可读的方式进行格式化。Java 14预览版增加了一个功能,使我们能够做到这一点。我们可以转义换行,使其被忽略:
public String getIgnoredNewLines() {
return """
This is a long test which looks to \
have a newline but actually does not""";
}
实际上这个String的字面意思只是等于一个正常的不间断的String:
@Test
void givenAStringWithEscapedNewLines_thenTheResultHasNoNewLines() {
String expected = "This is a long test which looks to have a newline but actually does not";
assertThat(subject.getIgnoredNewLines())
.isEqualTo(expected);
}
4.3.转义空格
编译器忽略了文本块中所有的尾部空格。然而,从Java 14预览版开始,我们可以使用新的转义序列\s来转义一个空格。编译器也会保留这个转义的空格前面的任何空格。
让我们来仔细看看转义空格的影响:
public String getEscapedSpaces() {
return """
line 1·······
line 2·······\s
""";
}
@Test
void givenAStringWithEscapesSpaces_thenTheResultHasLinesEndingWithSpaces() {
String expected = "line 1\nline 2 \n";
assertThat(subject.getEscapedSpaces())
.isEqualTo(expected);
}
注意:上面的例子中的空格被替换为‘-'符号,以使其清晰可见。
编译器将删除第一行中的空格。然而,第二行是以转义的空格结束的,因此所有的空格都被保留了。
5.格式化
为了帮助变量替换,我们增加了一个新的方法,允许在一个字符串字面上直接调用String.format方法:
public String getFormattedText(String parameter) {
return """
Some parameter: %s
""".formatted(parameter);
}
6.结语
在这个简短的教程中,我们研究了Java的文本块功能。它可能不会改变游戏规则,但它能帮助我们写出更好、更可读的代码,这通常是一件好事。
像往常一样,文章的完整源代码可以在GitHub上获得。