← 开发笔记

Java 字符串模板:JDK 21 预览、JDK 23 移除与替代方案

本文目录

字符串模板在 JDK 21 和 22 中是预览功能,在 JDK 23 中被移除。给 JDK 23 添加 --enable-preview 并不能恢复 STR。需要超越这些预览版本的代码应使用标准字符串 API 或针对目标格式的序列化器。Oracle 的移除说明解释了这一变化。

处理流程

图中展示的是标准 FormattingExample,而非历史预览示例。它比较三种格式化形式,并检查 MessageFormat 的单引号转义。

图中展示的是标准 FormattingExample,而非历史预览示例。它比较三种格式化形式,并检查 MessageFormat 的单引号转义。

哪个 JDK 能运行旧示例?

JDK 字符串模板状态 做法
21 预览 编译与运行都使用 JDK 21,并启用预览。
22 第二次预览 使用配套的 JDK 22 编译器、运行时与预览设置。
23 已移除 替换预览语法;选项无法恢复已移除的功能。

编译器的 --release 选项不能让新编译器恢复旧预览功能。Oracle 预览指南要求使用该预览版本对应的编译器。

运行历史 JDK 21 示例

将完整类保存为 Example.java。即使默认 JDK 是其他版本,本节也要求 JDK 21。

public class Example {
    public static void main(String[] args) {
        int x = 2;
        int y = 3;
        String result = STR."\{x} plus \{y} equals \{x + y}";
        System.out.println(result);
    }
}

确认所选工具,然后在文件所在目录编译并运行:

javac -version
java -version
javac --enable-preview --release 21 Example.java
java --enable-preview Example

输出为 2 plus 3 equals 5。编译时也会提示此类使用了预览功能。在这个 JDK 21 预览中,STR 被隐式导入;后续 JDK 缺少处理器的问题并不能靠添加 import 解决。参见 JDK 21 字符串模板指南。

用标准 API 替换预览语法

将以下内容保存为 FormattingExample.java。它使用标准 API,无需预览选项,完整类可在 Java 17 上工作。这里为 String.format 与 MessageFormat 显式指定区域设置,使数字输出可复现。

import java.text.MessageFormat;
import java.util.Locale;

public class FormattingExample {
    public static void main(String[] args) {
        int x = 2;
        int y = 3;
        System.out.println(x + " plus " + y + " equals " + (x + y));
        System.out.println(String.format(Locale.ROOT, "%1$d plus %2$d equals %3$d", x, y, x + y));
        MessageFormat format = new MessageFormat("{0} plus {1} equals {2}", Locale.ROOT);
        System.out.println(format.format(new Object[] {x, y, x + y}));
        System.out.println(new MessageFormat("It''s {0}", Locale.ROOT)
            .format(new Object[] {"ready"}));
    }
}
javac FormattingExample.java
java FormattingExample

输出:

2 plus 3 equals 5
2 plus 3 equals 5
2 plus 3 equals 5
It's ready
需求 适用 API 需保留的细节
简短表达式 + x + y 外的括号明确保留算术运算。
重复追加 StringBuilder 适合逐步构造文本。
格式字符串 String.format 或 .formatted %d 与 %s 遵循 Formatter 规则;需要显式区域设置时使用 String.format(Locale.ROOT, ...)。
本地化消息模式 MessageFormat 使用带编号的参数、对象数组与不同的引号规则。

MessageFormat 将单引号视为模式语法。It''s {0} 中双写的单引号生成上面显示的字面单引号。将 %s 模式换成 {0} 也意味着切换 API,并检查其区域设置行为。MessageFormat API、String API。

区分格式化与编码

STR 和普通格式化都不能让任意值成为安全的 JSON、SQL 或 HTML。应针对目标格式使用 JSON 序列化器、SQL 参数绑定或渲染系统的 HTML 转义。简单样例值看起来正确的字符串,遇到引号或反斜杠时仍可能失败。

两个完整类均曾用以上命令编译运行:预览示例使用 JDK 21.0.1,标准替代方案使用 JDK 17.0.8.1 与 21.0.1。表中的 JDK 22 和 23 行描述文档记载的功能历史,并未在此环境执行。

升级 JDK 还会影响框架兼容性。旧版 Spring 应用可参阅 Spring Boot 2.7 到 3.0 的迁移顺序。

讨论