JDK 21 预览、JDK 22 二次预览的"字符串模板"(String Templates,JEP 430 / JEP 459),原本被寄望取代丑陋的 String.format 和拼接。结果后来被正式撤回。作为一个写了七年后端的人,我反而觉得这次"撤回"是语言演进里难得的清醒。
它想解决什么
传统拼接两宗罪:易错、易注入。看这段:
// 老写法:顺序对不上就出 bug,且 SQL 拼接有注入风险
String q = "SELECT * FROM u WHERE name='" + name + "' AND age=" + age;
// 字符串模板写法(预览语法)
String q = STR."SELECT * FROM u WHERE name='\{name}' AND age=\{age}";
模板用 STR."..." 处理器,\{expr} 嵌入表达式,可读性确实好。但它野心不止于此——模板处理器(Template Processor)还能做校验、转义、甚至返回非字符串对象(比如直接返回安全的 SQL 对象),这是 String.format 做不到的。
争议在哪里
JEP 430/459 的设计有个核心张力:模板处理器既能"格式化"又能"校验/转义",把两种职责混在一起。社区里不少人担心:
- 语义过重:一个
STR看似简单,背后是可组合的处理器链,学习曲线陡; - 安全边界模糊:如果开发者自定义处理器忘了转义,反而制造"看起来安全其实不安全"的假象,比显式转义更危险;
- 与现有生态冲突:现有大量代码用
MessageFormat、日志框架的{}占位符,新语法要另立一套,迁移成本不低。
为什么撤回是好事
Java 语言团队最终决定撤回(withdraw),重新设计。我赞同,理由有三:
- 语言特性一旦 GA 就几乎不可逆,Preview 阶段发现方向分歧,撤回比硬上强;
- 把"格式化"和"安全校验"拆开,可能比塞进一个模板处理器更清晰——比如文本块(Text Blocks,JDK 15)已经解决多行问题,剩下的是校验,可以用别的 API;
- Java 的口碑建立在"稳"上,为一个锦上添花、且设计未收敛的语法冒险,不值。
对我的实际影响
几乎为零。我们从没在生产用预览特性——预览语法要加 --enable-preview,CI 和运维都不让过。撤回与否,我的代码还是 String.format 和占位符。但它给我一个提醒:语言特性不是越多越好。曾经追过的 Lambda、Stream 是真香,但那些"看起来很美"的语法糖,落地时往往暴露出和工程现实(静态分析、可维护性、团队认知)的摩擦。
一点延伸思考
对比下,JEP 444 虚拟线程能成,是因为它解决了真实痛点(并发复杂度),且对存量代码几乎零侵入。字符串模板的挫败,恰恰反衬出:好的语言演进要"解决真问题 + 低迁移成本 + 语义清晰"。三者缺一,就容易在预览阶段争议不断。撤回不是失败,是给设计留了退路——这点比特性本身更值得其他语言团队学。
先到这
《Java 字符串模板被撤回的反思》这块我前前后后踩了不止一次。今天先写这些,后面想到新的再补。