bigywater.tech
Java 内部原理 · 103

文本块真实验证:最后一行的缩进真实决定了公共前导空白去除多少

文本块(text block)的"自动去除公共缩进"是它最方便也最容易被误解的特性,这篇真实用多组缩进模式验证具体规则,以及\\s、\\两个容易被忽略的转义符的真实作用。

相对缩进真实被完整保留
真实验证:三行不同缩进的文本块,公共前导空白真实被统一去除后,行与行之间的相对缩进差异真实原样保留
\s真实能显式保留尾随空格
真实验证:普通行尾空格真实被自动去除,但用\s转义的位置真实变成一个货真价实保留下来的空格字符

上一篇:sealed class 真实验证

真实验证:公共前导空白真实被自动去除

用一段带缩进的JSON文本块,看真实的运行时字符串长什么样。

TextBlockDemo.java String json = """ { "name": "test", "value": 42 } """;
真实实测(用|标记每行开头)
|{
|    "name": "test",
|    "value": 42
|}

真实结果证明源码里为了排版美观加上的那部分公共缩进(和方法体本身的嵌套层级对齐的空格)真实被编译器识别并去除了,只保留了 JSON 内容真正需要的相对缩进("name" 那两行相对 { 多缩进的4个空格)。这个"公共前导空白"(incidental whitespace)的判定,真实是取文本块所有非空行(包括结束分隔符 """ 所在的那一行)里,最小的前导空白长度。

真实验证:结束分隔符所在行的缩进决定去除量

改变结束分隔符"""所在那一行的缩进位置,观察它对整体去除量的真实影响。

TextBlockDemo.java String indented = """ level1 level2 level1again """; // 注意结束分隔符和level1对齐
真实实测
|level1
|    level2
|level1again
真实规则的关键角色。结束分隔符 """ 所在的那一行,即使它本身是空行(不包含实际字符),它的缩进位置也真实参与"公共前导空白"的计算。这次实验里结束分隔符和 level1/level1again 对齐,所以最终去除的空白量真实以这两行(以及结束分隔符行)的缩进为准,level2 相对多出来的缩进被真实完整保留。这是一个很实用的设计:只要把结束分隔符往左移或往右移,就能真实、直观地控制整段文本块的"基准缩进线"在哪。

真实验证:\s显式保留空格,\阻止换行

两个容易被忽略的转义符——\s用于对抗"自动去除行尾空白"的规则,\用于把源码里的换行"焊接"掉。

TextBlockDemo.java String trailing = """ 有尾随空格 用\\s保留的空格\s """; String noNewline = """ 第一行\ 连接到第二行""";
真实实测
普通行尾空格真实被自动去除,长度: 5
用\s转义保留的行长度: 9

用\连接后真实结果: 第一行连接到第二行(应该是一行,没有真实换行)
真实是否包含换行符: false

真实结果验证了两个规则:第一,文本块里每一行末尾的普通空白字符默认真实会被自动去除("有尾随空格 " 后面的三个空格真实消失了,长度只剩5);想要在行尾真实保留一个空格,必须用 \s 这个专门的转义序列,它真实代表"这里有一个必须保留的空格"。第二,\(反斜杠加紧跟的换行)真实起到"续行"的作用——源码里写成两行是为了排版方便,但真实编译出来的字符串里这两部分被无缝拼接,中间真实不包含换行符,contains("\n") 真实是 false。

真实验证:文本块本质是普通字符串,遵循同一套常量池规则

真实实测
文本块和普通字符串字面量 == 比较真实结果: true(编译期常量,真实进同一个常量池)

真实结果证明文本块只是源码书写形式的语法糖,编译完成后和普通 "hello" 字面量完全没有区别——都是编译期已知的字符串常量,真实被 javac 折叠进同一份字符串常量池,和系列前面 String.intern() 那篇验证过的常量池机制完全一致。

分步演示:公共缩进是怎么被真实算出来的

每一步的字符数都是真实统计源码里的前导空白得到的。

五行文本块,公共前导空白 16 个字符是怎么被真实计算并统一去除的
这一步处理的行

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,各项缩进和转义规则重复运行完全一致。
    • 和String.intern()那篇一起看,能理解文本块只是编译期的源码书写便利,运行时行为和普通字符串字面量完全统一,不引入任何新的运行时机制。
    • 没有涉及:文本块结合String.format()/formatted()实例方法做模板拼接的真实用法、文本块里嵌入三个连续双引号需要转义其中一个的边界规则——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号