Skip to content
Chapter 47 · Core Java

Java 15 Text Blocks ​

Why Multiline Strings Were Always a Pain ​

Before Java 15, writing multiline strings was one of those things that every Java developer dreaded. Two use cases pop up constantly in real projects, and both of them were genuinely painful to get right.

The first is SQL queries. When you need to write a database query inside your Java code, that query tends to span several lines. It has SELECT, FROM, WHERE, and JOIN clauses, and cramming it all onto one line makes it completely unreadable. So you end up writing something like this:

java
String query = "SELECT id, name, email\n" +
               "FROM users\n" +
               "WHERE active = true\n" +
               "ORDER BY name ASC";

The second is JSON strings. This comes up a lot in test cases, especially when you are verifying that a method returns the exact JSON you expect. You have to write that expected JSON as a Java string, and it ends up looking like a tangle of escape characters and concatenation operators.

java
String json = "{\n" +
              "  \"name\": \"Alice\",\n" +
              "  \"country\": \"India\"\n" +
              "}";

Look at those strings carefully and count the problems. First, every double quote inside the string has to be escaped with a backslash. The JSON format uses double quotes everywhere, so every key and every string value becomes \". Second, every line break has to be written explicitly as \n. Third, you need string concatenation operators to join all those pieces together. The result is code that is enormously difficult to read. When your actual content is buried inside a wall of backslashes and plus signs and quoted fragments, it is very easy to make a mistake and not even notice it.

Consider this: if someone intentionally removes a comma from the JSON string to demonstrate a bug, can you spot it just by reading the code? Probably not, because the noise from all those special characters overwhelms your ability to read the actual content. That is exactly the problem. The code is error prone because mistakes are hard to see, hard to maintain because any edit requires carefully juggling escape characters, and completely useless for copy and paste because if you want to run that SQL query directly in your database tool you first have to strip out all the Java syntax.

Text blocks are the solution to every one of these problems.


What a Text Block Is ​

A text block is a multiline string literal introduced as a finalized feature in Java 15. It was available in preview form in Java 13 and 14, but Java 15 is where it became standardized and safe to use in production code.

The syntax uses three double quotes on each end:

java
String json = """
        {
          "name": "Alice",
          "country": "India"
        }
        """;

No escape characters for the double quotes inside. No \n at the end of each line. No string concatenation. You write the content exactly as it would look if you were editing it in a text file, and Java handles everything else.

The same applies to the SQL query:

java
String query = """
        SELECT id, name, email
        FROM users
        WHERE active = true
        ORDER BY name ASC
        """;

Compare that with the old version. The readability improvement is dramatic. You can copy the content directly from a database tool, paste it between the triple quotes, and it just works. No escaping, no reformatting.

It is important to understand what a text block actually is at the bytecode level. Internally, a text block compiles down to a regular String object. The compiler transforms the triple quoted content into the same kind of string with \n characters and escaped quotes that you would have written manually. So a text block is literally syntactic sugar. There is no new type, no new runtime behavior. The JVM does not even know the difference. The only thing that changes is how you write the string in your source code. Everything you can do with a regular string, you can do with a text block, because after compilation they are identical.


The Rules You Need to Know ​

Because the compiler has to transform your text block into a regular string, it follows a specific set of rules during that transformation. Understanding these rules is what separates developers who use text blocks confidently from those who get confused by the output they see.

Rule One: Content Cannot Start on the Opening Delimiter Line ​

The opening delimiter is the three double quotes that start your text block. The rule is simple: you cannot put any content on the same line as those opening triple quotes.

This is correct:

java
String block = """
        Hello
        World
        """;

This is a compile error:

java
String block = """Hello
        World
        """;

If you try the second form, the compiler tells you: illegal text block start, missing new line after opening quotes.

This keeps the indentation rule below simple: every content line starts at the left of the source line, so the compiler can compare their leading spaces.

Rule Two: Leading Whitespace Is Stripped Based on the Leftmost Content ​

This is the indentation rule, and it is the one that most people find surprising at first. When you write a text block inside a class and a method, your content is naturally indented:

java
public class Example {
    public static void main(String[] args) {
        String json = """
                {
                  "name": "Alice"
                }
                """;
    }
}

Those eight spaces before the opening curly brace are just indentation that you added to keep your code readable. You do not actually want those eight spaces to appear in the string value. Java handles this automatically.

The rule is: the compiler finds the leftmost piece of content across all lines of the text block, including the closing delimiter. It then removes that many spaces from the beginning of every line. Any spaces beyond that leftmost column are preserved, because they are part of the content's own formatting.

This means the closing """ controls indentation: moving it further left strips fewer spaces, so more indentation stays in the string. Placed at column zero, it strips nothing.

For example:

java
String block = """
        Line one
          Line two indented
        Line three
""";

Here the closing delimiter is at column zero, so it is the leftmost line. Zero spaces are stripped: Line one and Line three keep all 8 leading spaces and Line two indented keeps 10. Put the closing """ in line with the content (8 spaces) and the 8 spaces are stripped instead, leaving Line two indented with just its 2 extra spaces.

The practical takeaway: you can confidently use text blocks inside deeply nested code without worrying that your indentation will bleed into the string value. Java strips exactly the right amount of leading whitespace automatically.

Rule Three: Trailing Whitespace Is Stripped by Default ​

By default, any whitespace at the end of a line inside a text block is removed during compilation. This is usually what you want. Trailing spaces in a string are almost never intentional, and stripping them prevents subtle bugs where two strings that look identical differ because of invisible trailing spaces.

However, there are cases where you genuinely need trailing whitespace. Maybe you are generating a format where trailing spaces matter. For that situation, Java provides a special escape sequence: \s.

\s is an escape for a single space. Trailing spaces are stripped before escapes are processed, so the spaces before \s are no longer "trailing" and are kept, and \s itself adds one more space.

java
String padded = """
        apple   \s
        banana  \s
        cherry  \s
        """;

The line becomes apple followed by 4 spaces (3 typed + 1 from \s).

Rule Four: Line Continuation With Backslash ​

Every content line in a text block ends with a newline character. If the closing """ is on its own line, the last content line gets one too, so five content lines give five \n characters. (Put the closing """ right after the last word to avoid the final newline.)

Sometimes you do not want that. Imagine you have a very long URL that you want to split across two source lines for readability, but the URL itself should be a single unbroken string with no newline in the middle. Or imagine any situation where you want the logical content to continue on the next source line without a newline character separating them.

For this case, Java provides the line continuation character: a backslash at the very end of a line.

java
String url = """
        https://example.com/api/v1/users\
        ?page=1&limit=100&sort=name
        """;

Because the first line ends with \, the compiler does not insert a newline character between users and ?page. The two source lines join together into one continuous string. The backslash itself does not appear in the output.

This lets you break long strings across multiple source lines for readability without changing the actual string value.


Text Blocks Are Still Strings: Using Methods and Interpolation ​

Because a text block compiles to a regular String object, every method in the String class works on it. You can call .toUpperCase(), .trim(), .replace(), .length(), or any other string method directly on a text block.

java
String result = """
        hello world
        """.toUpperCase();

That works exactly as you would expect. The text block produces a string, and then toUpperCase() runs on that string.

One particularly useful method for text blocks is formatted(). This method works exactly like String.format() but you call it directly on the string itself. You can use %s placeholders inside the text block and then pass values to formatted() to fill them in:

java
String message = """
        Name: %s
        Country: %s
        """.formatted("Alice", "India");

The first %s receives "Alice" and the second receives "India". The result is a string with those values substituted in. This pattern is extremely clean for building template style output, especially for things like HTML fragments, JSON payloads, or email bodies where the structure is fixed but some values are dynamic.


Check yourself ​

  1. Since which Java version are text blocks standard?
  2. Why does String s = """Hello fail to compile?
  3. Content lines have 8 spaces of indentation and the closing """ is at column 0. How many spaces are stripped?
  4. How do you keep trailing spaces on a line?
  5. How do you split one long line across two source lines without adding \n?
  6. Is a text block a different type from String?
  7. How do you put values into a text block template?
Answers
  1. Java 15 (preview in 13 and 14).
  2. Content cannot be on the same line as the opening """; a line break must follow it.
  3. None. The closing delimiter is the leftmost line, so the minimum indentation is 0.
  4. End the line with \s.
  5. End the first line with a backslash \.
  6. No, it compiles to an ordinary String.
  7. Use %s placeholders and call .formatted(...).