本文最后更新于 429 天前,其中的信息可能已经有所发展或是发生改变。
我们都知道在很多流行语言中都拥有字符串模板(或者叫模板字面量)这种语法存在,但在java中,并没有这种语。
但在JEP378(即JDK15)中,交付了一个名为Text Blocks的特性,这是一个允许在java语法中跨越多行文本的特性,但遗憾的是其并不支持支持对于在字符串模板中进行变量的插值行为,其String::formatted方法可能有助于想使用模板字符串插值的开发者。
其Text Blocks插值方式:
String code = """
public void print($type o) {
System.out.println(Objects.toString(o));
}
""".replace("$type", type);
String code = String.format("""
public void print(%s o) {
System.out.println(Objects.toString(o));
}
""", type);
String source = """
public void print(%s object) {
System.out.println(Objects.toString(object));
}
""".formatted(type);
不过在2021年9月创建了一个新的JEP,其名为String Templates,这是一个探索字符串模板中插值行为的可能性的一个issue,其目标是为所有字符串形式提供插值行为,而不仅限于Text Blocks方式。
这是其规定语法的一部分:
STR模板方式
// Embedded expressions can be strings
String firstName = "Bill";
String lastName = "Duck";
String fullName = STR."\{firstName} \{lastName}";
| "Bill Duck"
String sortName = STR."\{lastName}, \{firstName}";
| "Duck, Bill"
// Embedded expressions can perform arithmetic
int x = 10, y = 20;
String s = STR."\{x} + \{y} = \{x + y}";
| "10 + 20 = 30"
// Embedded expressions can invoke methods and access fields
String s = STR."You have a \{getOfferType()} waiting for you!";
| "You have a gift waiting for you!"
String t = STR."Access at \{req.date} \{req.time} from \{req.ipAddress}";
| "Access at 2022-03-25 15:34 from 8.8.8.8"
以及其多行文本的插值方式:
String title = "My Web Page";
String text = "Hello, world";
String html = STR."""
<html>
<head>
<title>\{title}</title>
</head>
<body>
<p>\{text}</p>
</body>
</html>
""";
| """
| <html>
| <head>
| <title>My Web Page</title>
| </head>
| <body>
| <p>Hello, world</p>
| </body>
| </html>
| """
String name = "Joan Smith";
String phone = "555-123-4567";
String address = "1 Maple Drive, Anytown";
String json = STR."""
{
"name": "\{name}",
"phone": "\{phone}",
"address": "\{address}"
}
""";
| """
| {
| "name": "Joan Smith",
| "phone": "555-123-4567",
| "address": "1 Maple Drive, Anytown"
| }
| """
String description = "hammer";
double price = 7.88;
int quantity = 3;
double tax = 0.15;
String form = STR."""
Desc Unit Qty Amount
\{description} $\{price} \{quantity} $\{price * quantity}
Subtotal $\{price * quantity}
Tax $\{price * quantity * tax}
Total $\{price * quantity * (1.0 + tax)}
""";
| """
| Desc Unit Qty Amount
| hammer $7.88 3 $23.64
|
| Subtotal $23.64
| Tax $3.546
| Total $27.186
| """
FMTR
模板插值方式:
String description = "hammer";
double price = 7.88;
int quantity = 3;
double tax = 0.15;
String form = FMTR."""
Desc Unit Qty Amount
%-10s\{description} $%5.2f\{price} %5d\{quantity} $%5.2f\{price * quantity}
Subtotal $%5.2f\{price * quantity}
Tax $%5.2f\{price * quantity * tax}
Total $%5.2f\{price * quantity * (1.0 + tax)}
""";
| """
| Desc Unit Qty Amount
| hammer $ 7.88 3 $23.64
|
| Subtotal $23.64
| Tax $ 3.55
| Total $27.19
| """
原有的方式进行插值的:
# 如果开发人员忘记使用STR或者FMTR之类的模板策略怎么办?例如:
String name = "Joan";
String info = "My name is \{name}";
| error: incompatible types: java.lang.TemplatedString cannot be converted to java.lang.String
String html = """
<html>
<head>
<title>\{title}</title>
</head>
...
</html>
""";
| error: incompatible types: java.lang.TemplatedString cannot be converted to java.lang.String
# 当嵌入表达式出现在传统的字符串文字或文本块中,而不是出现在字符串模板表达式的模板中时,结果不是String而是TemplatedString。这个可以直接看:
String name = "Joan";
TemplatedString ts = "My name is \{name}"; // Compiles OK
# 字符串模板表达式STR."..."是调用模板策略apply方法的快捷方式。STR也就是现在熟悉的例子:
String name = "Joan";
String info = STR."My name is \{name}";
# 是一个快捷方式:
String name = "Joan";
TemplatedString tmp = "My name is \{name}";
String info = STR.apply(tmp);
# 字符串模板表达式的设计故意使从带有嵌入表达式的字符串文字直接转到String带有插入表达式值的字符串是不可能的。这避免了危险的错误字符串在程序中传播。字符串文字被用作一个TemplatedString类,不能与String混淆,或者字符串文字由模板策略处理,模板策略明确负责安全地插入和验证结果(String或其他)。
由于其未在任何新的JDK feature中提出,所以在JDK 20草案出来之前,我们都应该是看不到改JEP的实施的了。