Appearance
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\": \"Shriange\",\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": "Shriange",
"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.
Why does this rule exist? The answer is that it makes the compiler's job of stripping indentation much easier. Think about what the compiler needs to do: it has to figure out how many leading spaces to remove from each line. If content were allowed on the opening delimiter line, you could have zero spaces before some content and four spaces before other content, and the compiler would not know which amount to use as the baseline. By requiring all content to start from the line after the opening delimiter, the compiler can look at every line of content together and make a consistent decision.
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": "Shriange"
}
""";
}
}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 if you move the closing """ further to the left, you change how many leading spaces are stripped. By positioning the closing delimiter at the far left margin, you can control the final indentation of the entire content.
For example:
java
String block = """
Line one
Line two indented
Line three
""";Here the closing delimiter is at column zero. The leftmost content is the lines with eight spaces of indentation. After stripping those eight spaces, you get the content with its relative indentation preserved. Line two indented still has two extra spaces relative to Line one because those two spaces exist beyond the leftmost column.
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.
You place \s at the position where you want the line to end, and all spaces before that marker are preserved. Everything to the right of \s gets trimmed as usual, but everything to its left is kept.
java
String padded = """
apple \s
banana \s
cherry \s
""";In the compiled string, those spaces before \s are present in the output.
Rule Four: Line Continuation With Backslash
Every line in a text block automatically contributes a newline character to the resulting string. That is the default behavior. So if your text block has five lines of content, the compiled string has four newline characters embedded in it.
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("Shriange", "India");The first %s receives "Shriange" 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.
Interview Questions Around Text Blocks
Text blocks come up in Java interviews fairly often because they test whether you understand not just the feature itself but the rules that govern how the compiler processes them. Here are the questions you should be ready for.
What problem do text blocks solve?
Before text blocks, multiline strings in Java required explicit newline characters (\n), escaped double quotes (\"), and string concatenation to join lines together. This made code containing SQL queries, JSON, HTML, or XML extremely difficult to read, prone to mistakes, and impossible to copy and paste without stripping out Java syntax. Text blocks eliminate all of that.
When were text blocks finalized?
Java 15. They were in preview in Java 13 and 14, but Java 15 is the version where the feature became standard and production ready.
Can you put content on the same line as the opening triple quotes?
No. This is a compile error. The content must begin on the line after the opening """. This rule exists to give the compiler a clean baseline for calculating how much leading whitespace to strip.
How does Java decide how many leading spaces to remove?
It finds the leftmost piece of content across all lines, including where the closing delimiter sits. It removes that many spaces from the beginning of every line. Spaces beyond that leftmost position are preserved.
How do you control the indentation of the final string?
By positioning the closing """. Moving it further left strips more leading whitespace. Placing it at the very beginning of a line strips the maximum amount.
What happens to trailing whitespace?
It is stripped by default. If you need to preserve trailing whitespace on a line, place \s at the position where you want the line to end. Everything up to that marker is kept.
How do you prevent a newline from being inserted between two source lines?
End the first line with a backslash \. This is the line continuation character. The compiler joins the two lines without inserting a newline.
Are text blocks a new type?
No. A text block compiles to a regular java.lang.String object. At runtime, there is no difference between a text block and an ordinary string literal. Every string method works on text blocks, and you can assign them to String variables without any special handling.
What does the formatted() method do with text blocks?
It works like String.format() but is called as an instance method on the text block. You embed %s or other format specifiers in the content, then pass values to formatted(). It returns a new string with the placeholders replaced.
Putting It All Together
Text blocks are one of those features that you start using and immediately wonder how you lived without them. The amount of noise that disappears from your code when you switch from concatenated escape character strings to triple quoted text blocks is significant.
The rules are not complicated once you understand the reasoning behind them. The opening delimiter rule makes indentation calculation possible. The leftmost content rule strips exactly the indentation you added for code formatting and nothing more. The trailing whitespace rule prevents invisible bugs. The line continuation character gives you flexibility when you need a long logical line broken across multiple source lines. The \s escape gives you explicit control when you do need trailing spaces.
Start using text blocks in any Java 15 or later project whenever you are writing SQL, JSON, HTML, XML, configuration templates, or any other multiline string. The code becomes dramatically more readable, copy and paste just works, and mistakes in the content become easy to spot because they are no longer hidden behind escape characters and concatenation operators.
Because the feature is fully standardized, there is no risk in using it in production code. It is just a better way to write string literals, and the compiler handles all the transformation for you.