文本块(text block)的"自动去除公共缩进"是它最方便也最容易被误解的特性,这篇真实用多组缩进模式验证具体规则,以及\\s、\\两个容易被忽略的转义符的真实作用。
用一段带缩进的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
两个容易被忽略的转义符——\s用于对抗"自动去除行尾空白"的规则,\用于把源码里的换行"焊接"掉。
TextBlockDemo.java String trailing = """ 有尾随空格 用\\s保留的空格\s """; String noNewline = """ 第一行\ 连接到第二行""";
普通行尾空格真实被自动去除,长度: 5 用\s转义保留的行长度: 9 用\连接后真实结果: 第一行连接到第二行(应该是一行,没有真实换行) 真实是否包含换行符: false
真实结果验证了两个规则:第一,文本块里每一行末尾的普通空白字符默认真实会被自动去除("有尾随空格 " 后面的三个空格真实消失了,长度只剩5);想要在行尾真实保留一个空格,必须用 \s 这个专门的转义序列,它真实代表"这里有一个必须保留的空格"。第二,\(反斜杠加紧跟的换行)真实起到"续行"的作用——源码里写成两行是为了排版方便,但真实编译出来的字符串里这两部分被无缝拼接,中间真实不包含换行符,contains("\n") 真实是 false。
文本块和普通字符串字面量 == 比较真实结果: true(编译期常量,真实进同一个常量池)
真实结果证明文本块只是源码书写形式的语法糖,编译完成后和普通 "hello" 字面量完全没有区别——都是编译期已知的字符串常量,真实被 javac 折叠进同一份字符串常量池,和系列前面 String.intern() 那篇验证过的常量池机制完全一致。
每一步的字符数都是真实统计源码里的前导空白得到的。