← 返回题目列表

Java 的文本块(Text Blocks)是什么?怎么处理缩进和换行?

简单 第 19 / 24 题 更新于 2026/07/26
文本块Text Blocks多行字符串Java15

简化版

文本块(Text Blocks,Java 15 正式引入)是多行字符串的简洁写法——用三个双引号 """ 包裹一段跨多行的文本,不用再写一堆 \n 换行符和 + 拼接。特别适合写 SQL、JSON、HTML、XML 等多行内容,可读性大幅提升(所见即所得)。它自动处理换行(每行末尾自动加 \n),并有一套「去除公共缩进」的规则——编译器会自动删掉每行前面的公共空白(以内容最左边或结束 """ 的位置为基准),让你能在代码里正常缩进而不把缩进带进字符串。它是编译期语法糖,运行时就是普通的 String

详细版

传统多行字符串 vs 文本块

// 传统写法:\n 换行 + + 拼接,难读难维护
String json = "{\n" +
              "  \"name\": \"Tom\",\n" +
              "  \"age\": 18\n" +
              "}";

// 文本块:所见即所得
String json = """
        {
          "name": "Tom",
          "age": 18
        }""";
// 内容就是花括号里那几行,换行自动处理,引号不用转义

核心规则

规则说明
开始 """ 后必须换行""" 后面必须紧跟换行,内容从下一行开始
自动换行每行内容末尾自动加 \n(除了最后一行看 """ 位置)
去除公共缩进编译器删除所有行的公共前导空白(“附带缩进”)
引号不用转义里面的 " 不用写成 \"(除非连续三个 "
结尾 """ 位置影响缩进和末尾换行""" 越靠左,保留的缩进越少

去除公共缩进的机制

String text = """
        Hello
        World
        """;
// 三行内容前面都有 8 个空格(代码缩进)
// 编译器找"最小公共缩进"(这里所有行 + 结束 """ 的位置)→ 删掉这些公共空白
// 结果:"Hello\nWorld\n"(前导空格被去掉了)

几个控制符(Java 14+):

String s = """
        很长的一行想在代码里换行但\
        不想真的换行""";   // 行尾 \ 表示"这里不换行"(续行)

String t = """
        末尾要保留空格   \s
        """;             // \s 表示一个空格,防止行尾空格被去除

⚠️ 文本块去除的是「公共」前导空白(附带缩进 incidental whitespace),保留「相对」缩进(essential whitespace)。判断基准是「所有非空行的最小缩进」和「结束 """ 的位置」——取两者中更靠左的。所以你可以在代码里正常缩进文本块(为了代码美观),编译器会自动把这些「为了代码对齐的缩进」去掉,只保留文本本身该有的相对缩进(如 JSON 内部的层级缩进)。

完整版教学

一、文本块解决什么:多行字符串的痛苦

在文本块之前,Java 写多行字符串非常痛苦——要手动加 \n 换行、用 + 拼接、还要转义引号:

// 写一段 SQL,传统方式:
String sql = "SELECT u.name, u.age\n" +
             "FROM user u\n" +
             "WHERE u.status = 'ACTIVE'\n" +
             "  AND u.age > 18\n" +
             "ORDER BY u.age DESC";
// 问题:满屏的 \n 和 +,看不清 SQL 原貌,容易漏空格/写错,维护困难

痛点:\n+ 淹没了真正的内容(看 SQL 要在噪音里找);② 容易出错(漏个空格、少个 \n);③ 修改麻烦(每行都要维护引号和加号)。对于 SQL、JSON、HTML 这些「本身就是多行文本」的内容,这种写法尤其难受。文本块就是来终结这个痛苦的——让多行字符串在代码里「所见即所得」,你在代码里看到什么样,字符串就是什么样。

二、基本语法与自动换行

文本块用三个双引号 """ 开始和结束,中间是文本内容:

String sql = """
        SELECT u.name, u.age
        FROM user u
        WHERE u.status = 'ACTIVE'
        ORDER BY u.age DESC""";

两个基本规则:① 开始的 """ 后必须换行(内容从下一行开始,""" 那一行不能有内容);② 每行内容末尾自动加换行符 \n(你不用写 \n)。所以上面的 sql 实际值是 SELECT...\nFROM...\nWHERE...\nORDER BY...(每行之间有换行)。

引号处理也更友好:里面的单个/双个 " 不用转义WHERE name = "Tom" 直接写),只有连续三个 """ 才需要处理(会和结束符冲突)。这让写 JSON(满是双引号)变得轻松——不用把每个 " 都写成 \"。理解「""" 包裹、后必换行、自动加 \n、引号免转义」,就掌握了文本块的基本用法。

三、核心难点:去除公共缩进

文本块最需要理解的是「缩进处理」——它要解决一个矛盾:你想在代码里给文本块缩进(为了代码美观对齐),但又不想把这些代码缩进带进字符串。文本块的解法是「去除公共前导空白」:

String text = """
        Hello
        World
        """;
代码里三行内容前面都有 8 个空格(因为代码缩进):
        Hello       ← 8 空格 + Hello
        World       ← 8 空格 + World
        (结束 """ 也在 8 空格位置)

编译器的处理:
  1. 找所有行(含结束 """ 那行)的"最小公共缩进" = 8 个空格
  2. 把每行前面这 8 个公共空格删掉(这叫"附带缩进 incidental whitespace")
  3. 结果:"Hello\nWorld\n"(没有前导空格了)

关键概念:「附带缩进」(incidental whitespace,为代码对齐而加的公共缩进)被去除,「本质缩进」(essential whitespace,文本本身该有的相对缩进)被保留。这让你能在代码里自由缩进文本块(保持代码整洁),而字符串内容不受影响。这就是文本块「所见即所得」还能「代码里正常缩进」的秘密。

四、结束 """ 的位置:控制缩进基准

「最小公共缩进」的基准里有个关键角色——结束的 """ 的位置也参与计算,且它能用来精确控制保留多少缩进:

// 情况1:结束 """ 和内容对齐(都缩进 8 格)
String a = """
        Hello
        """;
// 公共缩进 = 8(内容和 """ 都是 8)→ 去掉 8 → "Hello\n"

// 情况2:结束 """ 更靠左(缩进 0)
String b = """
        Hello
""";
// 公共缩进 = 0(结束 """ 在最左,成了基准)→ 内容前的 8 空格被保留 → "        Hello\n"

规律:结束 """ 越靠左,去除的公共缩进越少(保留的前导空格越多)。因为它参与「最小公共缩进」的计算,它的位置成了「缩进删除的下界」。所以要精确控制文本块保留多少前导缩进,就调整结束 """ 的位置。实践中一般让结束 """ 和内容左对齐(去掉所有代码缩进,得到干净的文本),或按需靠左保留部分缩进。理解「结束 """ 位置决定缩进基准」,就能精确控制文本块的缩进。

五、末尾换行与续行符

两个常见的控制需求:控制末尾有没有换行长行在代码里折行但不真的换行

// 末尾换行:由结束 """ 的位置决定
String withNewline = """
        Hello
        """;       // 结束 """ 单独一行 → "Hello\n"(末尾有换行)
String noNewline = """
        Hello""";  // 结束 """ 紧跟内容 → "Hello"(末尾无换行)

// 续行符 \:行尾的 \ 表示"这里不换行"(把物理上的两行连成逻辑上的一行)
String longLine = """
        这是很长的一行,在代码里\
        换行显示但字符串里不换行""";
// 结果:"这是很长的一行,在代码里换行显示但字符串里不换行"(\ 消除了换行)

// \s:表示一个空格,防止行尾空格被自动去除(尾部空格默认会被删)
String s = """
        行尾要保留空格\s
        """;

要点:末尾换行看结束 """ 是否单独成行(单独一行则有 \n,紧跟内容则无);续行符 \(行尾)把两行连成一行(用于长行在代码里折行显示但不真换行);\s 保留一个空格(因为文本块默认会去除每行尾部的空白)。这几个控制符让文本块能精确表达各种换行/空格需求。

六、适用场景与注意点

文本块最闪光的场景是「内嵌的多行结构化文本」:

场景好处
SQL 语句所见即所得,一眼看清 SQL 结构,不用拼 \n
JSON / XML引号不用转义,层级缩进清晰
HTML 模板直接写标签,可读性高
多行提示文本、帮助信息排版直观

注意点:① 文本块运行时就是普通 String(编译期就处理成带 \n 的字符串,运行时无差别,可以正常做 +.length() 等);② 不适合频繁拼接变量——文本块本身不支持插值(Java 没有字符串模板,String Templates 曾预览但被移除),要插入变量还是用 String.format+③ 注意平台换行符——文本块统一用 \n,不受平台影响(不会因 Windows/Linux 而不同)。总之,文本块是「写多行静态文本」的利器,但不是「动态拼接」的方案。用对场景(写死的 SQL/JSON/HTML 模板),它能大幅提升可读性。

记忆钩子:「文本块(Java 15)= """ 包裹的多行字符串,写 SQL/JSON/HTML 所见即所得;后必换行、每行自动加 \n、引号免转义;去除『附带缩进』(公共前导空白)保留『本质缩进』,基准是最小公共缩进 + 结束 """ 位置;末尾换行看 """ 是否单独成行,\ 续行、\s 保留空格;运行时就是普通 String」

七、常见误区与追问

  • 误区:文本块是一种新的字符串类型。 不是——它编译后就是普通 String,运行时和用 \n++ 拼出来的字符串完全一样,只是写法更简洁。
  • 误区:文本块里的所有缩进都会保留。 不会——编译器去除「公共前导空白(附带缩进)」,只保留「相对缩进(本质缩进)」,让你能在代码里正常缩进而不带进字符串。
  • 误区:文本块支持插入变量。 不支持插值——文本块是静态文本,插变量还得用 String.format 或 +;Java 的字符串模板(String Templates)曾预览但已被移除。
  • 误区:""" 后可以直接跟内容。 不行——开始的 """ 后必须换行,内容从下一行开始;""" 那一行不能有内容。
  • 追问:文本块怎么控制末尾有没有换行? 看结束 """ 的位置——单独成一行则末尾有 \n,紧跟最后一行内容则末尾无换行。
  • 追问:怎么去除或保留文本块的前导缩进? 由「最小公共缩进」决定,基准包括所有内容行和结束 """ 的位置——结束 """ 越靠左保留的缩进越多;让它和内容左对齐可去掉所有代码缩进。
  • 追问:文本块行尾的 \\s 是什么? \(行尾续行符)表示这里不换行、把两行连成一行;\s 表示一个空格,用于保留默认会被去除的行尾空格。

八、加强记忆

文本块(Text Blocks,Java 15 正式)是多行字符串的简洁写法——用 """ 包裹跨多行的文本,专治 SQL/JSON/HTML/XML 这类多行内容的书写痛苦(不用再满屏 \n+、引号也免转义),所见即所得。基本规则:开始 """ 后必须换行每行末尾自动加 \n引号免转义。核心难点是缩进处理——编译器去除「附带缩进」(为代码对齐加的公共前导空白 incidental whitespace)、保留「本质缩进」(文本本身的相对缩进 essential whitespace),判断基准是「所有内容行 + 结束 """ 位置」的最小公共缩进,所以你能在代码里正常缩进而不把缩进带进字符串(结束 """ 越靠左保留缩进越多)。控制符:末尾换行看 """ 是否单独成行行尾 \ 续行(两行连一行)、\s 保留一个空格。它是编译期语法糖,运行时就是普通 String(可正常操作),但不支持变量插值(插变量用 String.format/+),适合写静态多行文本而非动态拼接。一句话「""" 多行字符串所见即所得、后必换行自动加 \n、去公共缩进保相对缩进、结束 """ 位置控缩进、运行时是普通 String 不支持插值」。