How does the compiler strip incidental whitespace from a text block, and what determines the minimal indentation?
answer
- Incidental vs essential whitespace
- Minimum over non-blank lines + closing-delimiter line
- Closing """ position sets the baseline
- Trailing whitespace always stripped
- String::stripIndent does it at runtime
basics
~20 sThe compiler removes the common leading whitespace shared by every non-blank line and the closing delimiter line. So you can indent the block to match your code, and that indentation is dropped from the result.
solid answer
~50 sText-block content has two kinds of leading whitespace: incidental (indentation added just to line up with the surrounding code) and essential (indentation you actually want in the string). The compiler determines the minimum indentation by looking at all non-blank content lines AND the line containing the closing delimiter, finding the smallest number of leading whitespace characters among them, and stripping exactly that many from every line. The closing delimiter's position is the key lever: moving the closing """ further left reduces the common minimum and therefore preserves more indentation in the result; moving it to the far left preserves all of it. Blank lines do not contribute to the minimum (they are not counted), but trailing whitespace on each line is also removed. You can call String::stripIndent yourself to apply the same algorithm at runtime.
code
java · 13 linesString aligned = """
SELECT id, name
FROM users
WHERE active = true
""";
// closing """ aligned under the content -> 8 incidental spaces stripped:
// "SELECT id, name\nFROM users\nWHERE active = true\n"
String kept = """
SELECT id
""";
// closing """ at column 0 -> minimum is 0 -> nothing stripped:
// " SELECT id\n"go deeper
Know that you can indent the block to match code and the alignment spaces get removed.
Explain incidental vs essential whitespace, that the minimum is taken across non-blank lines plus the closing delimiter, and that trailing whitespace is stripped.
Demonstrate controlling the baseline via the closing delimiter's column, note tabs count as single characters, and mention String::stripIndent.
Advise team conventions (closing-delimiter placement, tab/space consistency, formatter settings) to keep text-block values stable and reviewable across the codebase.
## The problem being solved When you embed a text block in indented code, you naturally indent the *content* too so it lines up: ```java void m() { String s = """ line one line two """; } ``` The spaces before `line one` are there only to align with the code — they are **incidental whitespace**. You almost certainly do not want them in the actual string. But spaces you add *beyond* that, to indent text within the block, are **essential whitespace** you do want. ## The stripping algorithm The compiler separates incidental from essential automatically: 1. Take all the content lines, **plus the line that contains the closing delimiter**. 2. Ignore lines that are entirely blank (all-whitespace or empty) when computing the minimum — they do not lower the count. 3. For every remaining line, count the number of **leading white-space characters** (spaces and tabs). 4. The **minimum** of those counts is the amount of *common* (incidental) indentation. 5. Strip exactly that many leading characters from **every** line (including blank ones, as far as they have them). 6. Separately, **trailing whitespace** is removed from the end of every line. The result keeps only the *essential* indentation — the part beyond the common minimum. ## The closing delimiter is the control knob Because the closing-delimiter line participates in the minimum calculation, **where you put `"""` decides the baseline**: - Closing `"""` aligned with the content → the content's indentation becomes the minimum → all of it is incidental → stripped. - Closing `"""` pushed all the way to column 0 → minimum becomes 0 → **no** indentation is stripped; every leading space is preserved. Example — these differ only in the closing delimiter's column: ```java String a = """ hi """; // closing aligned -> "hi\n" (no leading spaces) String b = """ hi """; // closing at col 0 -> " hi\n" (8 spaces kept) ``` ## Tabs and spaces The count is of *characters*, not visual columns, so a tab counts as one leading whitespace character regardless of tab width. Mixing tabs and spaces for indentation can therefore produce surprising results — keep it consistent. ## Doing it manually The same algorithm is exposed as the instance method **`String::stripIndent`**, so you can apply it to any string at runtime, not just to text-block literals. ## Why this design It lets the source *look* nicely indented while the *value* stays clean, with the closing delimiter giving you explicit, visible control over the baseline rather than relying on a hidden rule.
- If the closing delimiter is on a line by itself at column 0, what happens to indentation?The minimum common indentation becomes 0, so no leading whitespace is stripped — every line keeps its full indentation in the resulting string.
- How can you apply the same stripping logic to a non-literal string at runtime?Call String::stripIndent() on it; it runs the same incidental-whitespace algorithm used for text-block literals.
- Do blank lines affect the computed minimum indentation?No. Entirely blank lines are excluded from the minimum calculation, though they still have their leading whitespace stripped up to that minimum.
saying these in an interview costs you the question
- Saying all leading whitespace is always stripped (it is not — only the common minimum)
- Forgetting the closing-delimiter line participates in the minimum
- Claiming blank lines lower the minimum indentation
- Thinking a tab equals 4 or 8 leading characters in the count