1. Introduction
1.导言
In this tutorial, we’ll talk about Java’s answer to String interpolation – String templates. This pre-release preview feature was introduced as part of Java 21 with JEP 430.
在本教程中,我们将讨论 Java 对字符串插值的回应–字符串模板。作为 Java 21 的一部分,JEP 430 引入了这一预发布预览功能。
2. String Composition in Java
2.Java 中的字符串合成
We use Strings to represent sequences of numbers, letters, and symbols to represent text in code. Strings are ubiquitous in programming, and we often need to compose strings to use in code. There are several ways to do that, and each technique has its downsides.
我们使用 Strings 来表示数字、字母和符号的序列,从而在代码中表示文本。Strings 在编程中无处不在,我们经常需要将字符串组成代码。有几种方法可以做到这一点,每种技术都有其缺点。
2.1. String Concatenation
2.1.字符串连接
String concatenation is the most basic action we use to build strings. We take strings literals and expressions and then use the + symbol to compose them together:
String concatenation 是我们用来构建字符串的最基本操作。我们使用字符串字面量和表达式,然后使用 + 符号将它们组合在一起:
String composeUsingPlus(String feelsLike, String temperature, String unit){
return "Today's weather is " + feelsLike +
", with a temperature of " + temperature + " degrees " + unit;
}
This code achieves the desired functionality but is hard to read, especially with all the plus symbols, and also difficult to maintain and change.
该代码实现了所需的功能,但难以阅读,尤其是所有的加号符号,而且难以维护和更改。
2.2. StringBuffer or StringBuilder
2.2.StringBuffer 或 StringBuilder
We can use utility classes Java provides, such as the StringBuilder and StringBuffer classes. These classes provide us with the append() library function to compose strings, thereby removing the usage of + in string composition:
我们可以使用 Java 提供的实用程序类,例如 StringBuilder 和 StringBuffer 类。这些类为我们提供了append() 库函数来组合字符串,从而消除了在字符串组合中使用 + 的情况:
String composeUsingStringBuilder(String feelsLike, String temperature, String unit) {
return new StringBuilder()
.append("Today's weather is ")
.append(feelsLike)
.append(", with a temperature of ")
.append(temperature)
.append(" degrees ")
.append(unit)
.toString();
}
StringBuilder and StringBuffer classes provide efficient String manipulation and composition techniques while reducing memory overheads. However, they follow the Builder design pattern and hence become quite verbose.
StringBuilder 和 StringBuffer 类提供了高效的字符串操作和组合技术,同时减少了内存开销。然而,它们遵循 Builder 设计模式,因此变得相当冗长。
2.3. String Formatter
2.3 字符串格式化器
Java provides us with the capability to separate the static part of the String and the parameters, such as the temperature and the unit with the String.format() or the formatted() methods:
Java 允许我们使用 String.format() 或 formatted() 方法来分离字符串的静态部分和参数,例如 temperature 和 unit :
String composeUsingFormatters(String feelsLike, String temperature, String unit) {
return String.format("Today's weather is %s, with a temperature of %s degrees %s",
feelsLike, temperature, unit);
}
The base template string remains static. However, the order and the number of arguments passed here are crucial for the correctness of its response.
基本模板字符串保持不变。但是,这里传递的参数顺序和数量对响应的正确性至关重要。
2.4. MessageFormat Class
2.4 MessageFormat 类
Java provides a MessageFormat class of the Java.text package that helps in the composition of text messages with placeholders for dynamic data. Localisation and Internationalisation heavily use this. We can use MessageFormat.format() in plain String composition:
Java 提供了Java.text包中的MessageFormat类,该类可帮助组成带有动态数据占位符的文本信息。Localisation 和 Internationalisation 大量使用了该类。我们可以在普通字符串组成中使用 MessageFormat.format() :
String composeUsingMessageFormatter(String feelsLike, String temperature, String unit) {
return MessageFormat.format("Today''s weather is {0}, with a temperature of {1} degrees {2}",
feelsLike, temperature, unit);
}
This also shares a similar downside as that of the above. Additionally, the syntax structure differs from how we write and use strings in code.
这也有类似的缺点。此外,语法结构与我们在代码中编写和使用字符串的方式不同。
3. Introduction to String Templates
3.字符串模板介绍
As we saw, all the String composition techniques mentioned above come with their shortcoming. Let’s see how String templates can help with those.
正如我们所看到的,上面提到的所有字符串合成技术都有其不足之处。让我们看看字符串模板如何帮助我们解决这些问题。
3.1. Goals
3.1.目标
String templates are introduced to the Java programming ecosystem with the following goals in mind:
将字符串模板引入 Java 编程生态系统的目的如下:
- Simplify the process of expressing Strings with values that can be compiled at run time
- Enhanced readability of String compositions, overcome the verbosity associated with StringBuilder and StringBuffer classes
- Overcome the security issues of the String interpolation techniques that other programming languages allow, trading off a small amount of inconvenience
- Allow Java libraries to define custom formatting syntax of the resulting String literal
3.2. Template Expressions
3.2.模板表达式
The most important concept of String templates revolves around template expressions, a new kind of programmable expressions in Java. Programmable template expressions can perform interpolation but also provide us with the flexibility to compose the Strings safely and efficiently.
可编程模板表达式不仅可以执行插值,还能为我们提供安全、高效地组成字符串的灵活性。
Template expressions can turn structured text into any object, not just limited to Strings.
模板表达式可将结构化文本转化为任何对象,而不仅限于字符串。
There are three components to a template expression:
模板表达式有三个组成部分:
- A processor
- A template which contains the data with the embedded expressions
- A dot (.) character
4. Template Processors
4.模板处理器
A template processor is responsible for evaluating the embedded expression (the template) and combines it with the String literal at runtime to produce the final String. Java provides the ability to use an inbuilt template processor, provided by Java, or switch it with a custom processor of our own.
模板处理器负责评估嵌入式表达式(模板),并在运行时将其与 String 字面结合,生成最终的 String 。
This is a preview feature in Java 21; hence, we would have to enable preview mode.
这是 Java 21 中的预览功能;因此,我们必须启用预览模式。
4.1. STR Template Processor
4.1. STR 模板处理器
Java provides some out-of-the-box template processors. The STR Template Processor performs string interpolation by iteratively replacing each embedded expression of the provided template with the stringified value of that expression. We will apply the STR processor String template in our previous example here:
Java 提供了一些开箱即用的模板处理器。 STR 模板处理器通过用表达式的字符串化值迭代替换所提供模板的每个嵌入式表达式来执行字符串插值。我们将在前面的示例中应用 STR 处理器字符串模板:
String interpolationUsingSTRProcessor(String feelsLike, String temperature, String unit) {
return STR
. "Today's weather is \{ feelsLike }, with a temperature of \{ temperature } degrees \{ unit }" ;
}
STR is a public static final field and is automatically imported into every Java compilation unit.
STR 是一个公共静态最终字段,会自动导入到每个 Java 编译单元中。
We can extend the above implementation not just to single-line Strings but to multiline expressions as well. For multiline text blocks, we surround the text block with “””. Let’s take the example of interpolating a String that represents a JSON:
我们不仅可以将上述实现扩展到单行字符串,还可以扩展到多行表达式。对于多行文本块,我们用 “”” 包围文本块。让我们以插值表示 JSON 的字符串为例:
String interpolationOfJSONBlock(String feelsLike, String temperature, String unit) {
return STR
. """
{
"feelsLike": "\{ feelsLike }",
"temperature": "\{ temperature }",
"unit": "\{ unit }"
}
""" ;
}
We can also inject expressions inline, which will compile at runtime:
我们还可以内联注入表达式,这些表达式将在运行时编译:
String interpolationWithExpressions() {
return STR
. "Today's weather is \{ getFeelsLike() }, with a temperature of \{ getTemperature() } degrees \{ getUnit() }";
}
4.2. FMT Template Processor
4.2.FMT 模板处理器
Another Java-provided processor is the FMT Template Processor. It adds the support of understanding formatters that are provided to the processor and format the data according to the formatting style provided.
另一个 Java 提供的处理器是 FMT 模板处理器。它增加了对提供给处理器的格式化器的理解支持,并根据提供的格式化样式对数据进行格式化。
The supplied formatter should be similar to java.util.Formatter:
提供的 formatter 应与 java.util.Formatter: 类似。
String interpolationOfJSONBlockWithFMT(String feelsLike, float temperature, String unit) {
return FMT
. """
{
"feelsLike": "%1s\{ feelsLike }",
"temperature": "%2.2f\{ temperature }",
"unit": "%1s\{ unit }"
}
""" ;
}
Here, we use %s and %f to format the string and the temperature in a specific format.
在这里,我们使用 %s 和 %f 以特定格式格式化字符串和温度。
4.3. Evaluation of a Template Expression
4.3.模板表达式的评估
There are a few steps involved in the evaluation of a template expression in the line:
在行中评估模板表达式有几个步骤:
STR
. "Today's weather is \{ feelsLike }, with a temperature of \{ temperature } degrees \{ unit }" ;
The above is a shorthand for several steps that we’ll see.
以上是我们将要看到的几个步骤的简写。
First, an instance of a template processor, StringTemplate.Processor<R, E> is obtained by evaluating the left of the dot. In our case, it is the STR template processor.
首先,通过对点的左边进行求值,可以获得模板处理器 StringTemplate.Processor<R, E> 的实例。在我们的例子中,它就是 STR 模板处理器。
Next, we obtain an instance of a template, StringTemplate, by evaluating to the right of the dot:
接下来,我们通过在点的右侧求值,得到一个模板 StringTemplate 的实例:
StringTemplate str = RAW
. "Today's weather is \{ getFeelsLike() }, with a temperature of \{ getTemperature() } degrees \{ getUnit() }" ;
RAW is the standard template processor that produces an unprocessed StringTemplate type object.
RAW 是标准模板处理器,可生成未经处理的 StringTemplate 类型对象。
Finally, we pass the StringTemplate str instance to the process() method of the processor(which in our case is STR):
最后,我们将 StringTemplate str 实例传递给处理器的 process() 方法(在本例中,处理器就是 STR) ):
return STR.process(str);
5. String Interpolation and String Templates
5.字符串插值和字符串模板
We have now seen examples of using String templates as a string composition technique, and we can see that it is very similar to String interpolation. However, String templates provide the safety that String interpolation on other platforms generally does not guarantee.
我们现在已经看到了使用字符串模板作为字符串组成技术的示例,可以看出它与字符串插值非常相似。不过,字符串模板提供了其他平台上字符串插值一般无法保证的安全性。
Template expressions are designed intentionally so that it is impossible to interpolate a String literal or text block containing an embedded expression to an output String directly. The processor’s presence ensures that dangerous or incorrect Strings do not propagate through the code. It is the processor’s responsibility to validate that the interpolation is safe and correct.
模板表达式的设计意图是不可能将包含嵌入式表达式的字符串字面或文本块直接插入到输出字符串中。处理器的存在可确保危险或不正确的字符串不会通过代码传播。
The absence of any template processor will generate a compile-time error. Also, if the processor fails to interpolate, it can generate an Exception.
没有任何模板处理器将产生编译时错误。此外,如果处理器插值失败,则会产生 Exception.
Java decides to treat “<some text>” as a StringLiteral or a StringTemplate based on the presence of the embedded expressions. The same is followed for “””<some text>””” to distinguish between TextBlock and TextBlockTemplate. This distinction is important to Java because even though, in both cases, it is wrapped between double quotes(“”), a String template is of type java.lang.StringTemplate, an interface, and not the java.lang.String.
Java 会根据嵌入表达式的存在决定将 “<some text>” 视为 StringLiteral 还是 StringTemplate 。“””<某些文本>”””也遵循同样的方法来区分 TextBlock 和 TextBlockTemplate。这种区分对 Java 很重要,因为即使在这两种情况下都用双引号(“”)包装,字符串模板也是 java.lang.StringTemplate 类型,是一个接口, 而不是 java.lang.String. 类型。
6. Conclusion
6.结论
In this article, we discussed several String composition techniques and understood the idea behind String interpolation. We also looked at how Java is introducing the idea of String interpolation with the help of String templates. Finally, we looked at how String templates are better and safer to use than the general String interpolation.
在本文中,我们讨论了几种字符串组成技术,并了解了字符串插值背后的思想。我们还了解了 Java 如何在字符串模板的帮助下引入字符串插值的思想。最后,我们了解了字符串模板如何比一般的字符串插值更好用、更安全。
As usual, the code is available over on GitHub.
与往常一样,代码可在 GitHub 上获取。