在Java 12中删除了类似的功能之后,Java 13终于为多行字符串文字提供了支持。
String literals in Java
在Java中声明字符串文字很容易:
String myString = "Behold, a string literal!";
没什么新鲜的吧? 但是,传统的字符串文字有一些不便的限制。
首先,整个文字只需要一行。 这对于简单的短字符串是可以的,但是对于较长的短字符串,则需要诉诸于连接多个字符串文字。 如果您还想包含换行符,则需要添加\ n。
String myString = "This is my string\n" +
"which I want to be \n" +
"on multiple lines.";
这麻烦且难以阅读。 另一个问题是各种字符不能直接表示,而需要转义,例如”要么\。 这使您的琴弦更加难以阅读和使用。
String path = "Open \"C:\\Program Files\\Java\\jdk1.8.0_152\"";
在正则表达式之类的情况下,这尤其麻烦。 但是该如何处理呢?
Other JVM languages
像往常一样,Java迟来了引入许多其他语言已经通用的功能,甚至是JVM上的那些语言。 Kotlin,Scala或Groovy已使用以下命令支持多行字符串文字“”记号而不是通常的”。 在Kotlin中查看以下示例。
val text = """
This is my cool string,
which I want to span
multiple lines.
It can have backslash \
and even double-quotes "
"""
如您所见,不仅是多行,而且您也不再需要转义字符。 这称为原始字符串文字,这意味着所有字符均按原样解释,无需转义。
Raw String literals in Java
In Java 12, there was originally proposal to include Raw String Literals (JEP-326). The behavior was very similar to the example in Kotlin above. But instead of using """"
as in other JVM languages, it used backtick notation. The concept was slightly unusual in a way that you could use any number of backticks and the same amount of backticks at the end. This way it was not necessary to escape backticks inside a spring literal no matter how many consecutive backticks were present.
原始字符串文字的一个问题通常是缩进。 多行原始字符串文字中的每个字符都按原样进行解释-包括缩进,该缩进应该是为了更好的代码可读性而不是文字本身的一部分。 考虑以下示例:
public static void main(String[] args) {
String myString =
`This is my string
which I want to be
on multiple lines.`;
System.out.println(myString);
}
如果您打印它,除第一行外的所有行都会有缩进。
This is my string
which I want to be
on multiple lines.
您可能需要使用新建议的String方法手动修复此问题align()和indent()。 不太实用,但是如果使用原始字符串,则必须忍受这一点。
You can read more about the original Raw String Literals proposal in the following article:
This proposal was, however dropped before the final release of Java 12 and is now considered obsolete.
虽然我们可以预期,对于任何语言功能,都会有大量的“我会不同地喜欢它”反馈,但是在回顾我们收到的反馈时,我不再相信我们已经选择了正确的设置 复杂性和表现力之间的权衡,或者我们已经探索了足够的设计空间,可以确信当前的设计是我们能做到的最好的选择。 通过撤消,我们可以继续优化设计,探索更多选项,并争取真正满足预览功能流程(JEP 12)要求的预览。
Multiline String literals in Java
After the withdrawal of the original proposal, the discussion was restarted and resulted in a brand new proposal, which will be introduced in Java 13 as a Preview Feature. Its called JEP 355: Text Blocks (Preview).
它不应该是Raw String Literals的实现,而应该是多行String文字,尽管您不需要全部使用它们,但仍然可以进行转义。 最重要的是,没有必要处理所有缩进问题,这对于Raw String Literals是必需的。
Preview Feature
文本块仅在Java 13中可用作预览功能。这是什么意思?
预览语言或VM功能是Java SE平台的一项新功能,该功能已完全指定,完全实现但不是永久性的。 JDK功能版本中提供了该功能,以根据实际使用情况激发开发人员反馈。 这可能会导致它在将来的Java SE平台中永久存在。在下一个JDK功能发行版之前,将评估该功能在“现实世界”中的优缺点,以确定该功能在Java SE平台中是否具有长期作用,如果是,则需要完善。 因此,可以为功能授予最终和永久状态(有或没有改进),或经过进一步的预览期(有或没有改进),或者将其删除。
JDK随附了此类功能,但默认情况下未启用。 您需要明确允许他们使用它们。 不用说,它不打算用于生产用途,而是用于评估和实验,因为在将来的发行版中可能会删除它或对其进行重大更改。
You'll need to download JDK 13. In IntelliJ, go to File → Project Structure
and make sure you have JDK 13 selected under Project SDK. To enable Text Blocks as a preview feature, be sure to select 13 (Preview) - Text blocks
under Project language level
.
手动构建应用程序时,您需要指定以下参数,以指定应启用预览功能:Java语言:
javac --release 13 --enable-preview ...
那是在编译时。 在运行时,您只需提供-启用预览
java --enable-preview ...
Text Blocks
与拒绝的原始字符串文字不同,文本块由三个双引号引起来“”“”,与Groovy或Kotlin中的相同。 它与纯字符串文字和其他JVM语言更加同步。
String myBlock = """
line 1
line 2
line 3
"""
文本块和字符串文字之间没有运行时差异。 两者都导致String的实例。 如果它们具有相同的值,它们将像往常一样被实习,并最终成为同一实例。 您可以在任何地方使用String文字,也可以使用文本块。
Processing
与常规String文字不同,Texts块由编译器分三步处理:
- 线端已标准化多余的空格被删除转义字符被解释
Line end normalization
Windows和基于UNIX的操作系统具有不同的字符来表示行尾。
Windows使用回车\ r和换行\ n,而基于Unix的系统仅使用换行。 问题是文本块直接使用源代码中的换行符,而不是使用\ n例如常规字符串文字。 这意味着在Windows上编译时,在Unix上创建的源代码将具有带有不同行尾的字符串。 弦线看起来与裸眼相同,但是具有不同的行尾。
为防止这种情况,Java编译器将所有行尾作为文本块,并将其归一化为换行\ n。 重要的是,此操作必须在评估转义字符之前完成。 这意味着如果您明确需要使用\ r,您可以,因为它在行结束规范化之后进行评估并且不会受到影响。
Indentation removal
还记得原始字符串文字和缩进的示例吗? 原始字符串文字会解释所有字符,包括缩进。 因此,原本只是为了使您的源代码易于阅读的空格实际上已成为字符串的一部分。 在绝大多数情况下,这不是理想的行为。
幸运的是,Java编译器在编译文本块时删除了不需要的空格。
- 从行尾删除所有尾随空格。从每行的开头删除前导的公共空格。
这到底是什么意思? 让我们看下面的代码:
public static void main(String[] args) {
String html = """
Hello, world
""";
}
HTML代码段包含大量空白,但实际上并不属于空白。 它只是使其在源文件中完全对齐。 重要的是块内的相对压痕。
换句话说:如果片段中的每一行都以22个空格开头,我们可以忽略它们。 这22个空格是通用空白前缀,可以忽略不计,仅保留最重要的内容。
让我们用替换普通前缀。。 All of these spaces will be discarded。 Only spaces marked with -- will be kept as they exceed the common whitespace prefix。
String html = """
..............
..............--
..............----Text Blocks are awesome!
..............--
..............
..............""";
结果将是:
Text Blocks are awesome!
请注意,在此步骤中,仅直接空格被删除。 如果您使用转义字符形式的空格,例如\ n要么\ t,它不会被删除。
Escaping
文本块不是原始字符串,您仍然可以使用转义符。 但是,您无需打扰最常见的对象。
- 新队\ n由于文本块本质上是多行的,因此不再需要。你不需要逃脱”双引号,因为它们不再标记字符串文字结尾
String myBlock = """
First line
Second Line with " quotes
"""
Since the quoting is allowed, you technically can include \n
and \"
, but it is not necessary and it is discouraged. You still do need to escape slash \\
. But in general Text Blocks involve a lot less escaping than good old String literals. All the escape sequences, which can be used in String literals, can be also used for Text Blocks. Check the Java spec for the full list.
将转义字符解释为三个步骤的最后一步非常重要,因为转义不受行尾规范化和空格删除的影响。
New String Methods
作为“文本块”提案的一部分,以下三种新方法串类。
- translateEscapes()-转换字符串中的转义序列(Unicode除外)。stripIndent()-从每一行的开头去除公共空格。格式化(对象...参数)-便捷方法,等效于String.format(string,args)
Conclusion
- 文本块提供了一种使用多行字符串文字的便捷方式。要创建文本块,只需将字符串用“”“”。您可以在任何可以使用字符串文字的地方使用文本块行尾被标准化为LFExtra whitespace is stripped from the beginning and the end of each line。Only relative indentation is preserved.它是Java 13中的预览功能,需要显式启用Raw String文字提案从Java 12中撤回; 稍后介绍了文本块