Text blocks (Java 15, JEP 378) are multi-line string literals enclosed
in triple double-quotes ("""). They eliminate the need for explicit \n,
\", and string concatenation when embedding multi-line content like JSON,
SQL, HTML, or XML.
// Old way — hard to read, easy to make mistakes:
String json = "{\n" +
" \"name\": \"Alice\",\n" +
" \"age\": 30\n" +
"}";
// Text block — reads like the actual content:
String json = """
{
"name": "Alice",
"age": 30
}
""";
Rule of thumb: use text blocks for any multi-line string — SQL,
JSON, HTML, XML, or test fixtures; never concatenate \n manually again.
- The opening
"""must be followed by a newline — content cannot start on the same line as the opening delimiter. - The closing
"""can be on its own line or at the end of the last content line. - The position of the closing
"""determines the amount of incidental whitespace stripped.
// Closing """ on its own line — trailing newline included:
String s1 = """
hello
world
""";
// s1 = "hello\nworld\n"
// Closing """ at end of last line — no trailing newline:
String s2 = """
hello
world""";
// s2 = "hello\nworld"
Rule of thumb: put the closing """ on its own line for content that
should end with a newline (files, SQL); inline it to suppress the trailing
newline.
Incidental whitespace is the leading spaces added to align a text block with the surrounding code indentation. The compiler removes it automatically, keeping only the relative indentation within the block.
The algorithm finds the common leading whitespace prefix across all non-blank content lines and the closing delimiter line, then strips that prefix from every line:
String sql = """
SELECT *
FROM users
WHERE active = true
""";
// Each content line has 12 spaces; closing """ has 12 spaces.
// Compiler strips 12 spaces → result:
// "SELECT *\nFROM users\nWHERE active = true\n"
You can increase relative indentation by indenting content lines more than the closing delimiter:
String indented = """
outer
inner
""";
// "outer\n inner\n" — inner has 4 extra spaces relative to outer
Rule of thumb: align the closing """ with the minimum indentation
you want in the output; the compiler strips everything up to that column.
The Java compiler normalises all line endings in text blocks to \n
(LF) regardless of the OS line ending in the source file. This makes
text blocks portable across Windows (CRLF) and Unix (LF) systems without
any special handling.
String s = """
line1
line2
""";
// Always "line1\nline2\n" — never "line1\r\nline2\r\n"
If you explicitly need \r\n (e.g., for HTTP headers or email), use
the \r escape:
String crlf = """
Content-Type: text/html\r
Content-Length: 42\r
\r
""";
Rule of thumb: text blocks use \n everywhere — don't worry about
CRLF portability; handle it explicitly only when the protocol requires it.
Java 15 added two new escape sequences specifically for text blocks:
\<line terminator> (line continuation) — suppresses the newline at
the end of a line, joining it with the next line. Useful for long logical
lines you want to wrap visually:
String sentence = """
The quick brown fox \
jumps over the lazy dog.
""";
// "The quick brown fox jumps over the lazy dog.\n"
\s (explicit space) — a single space that prevents trailing-space
stripping. The compiler strips trailing whitespace from each line; \s
marks a space that must be preserved:
String padded = """
red \s
green\s
blue \s
""";
// Each line ends with exactly one trailing space
Rule of thumb: use \ to join wrapped lines; use \s to preserve
trailing spaces that would otherwise be stripped.
Text blocks do not support template syntax natively. Use
String.formatted() (or String.format()) to substitute values:
String name = "Alice";
int age = 30;
String json = """
{
"name": "%s",
"age": %d
}
""".formatted(name, age);
// {"name":"Alice","age":30}
String.formatted() (added in Java 15) is the instance-method equivalent
of String.format(), making the chain read naturally after a text block.
Rule of thumb: use .formatted() for simple substitution; for
complex templates with loops or conditionals, prefer a template engine
(Mustache, Thymeleaf) rather than string manipulation.
No. A text block is just a compile-time literal that produces a
regular java.lang.String. At runtime there is no difference between a
text block and a regular String literal — they are the same type.
String a = "hello\nworld\n";
String b = """
hello
world
""";
System.out.println(a.equals(b)); // true — same content, same type
System.out.println(a == b); // likely true — interned constants
Because text blocks are string literals they are interned (pooled) just like regular literals.
Rule of thumb: treat text blocks as a nicer syntax for string literals — same type, same pool, same API.
Text blocks make multi-line SQL readable and maintainable, preserving the visual structure of the query:
String query = """
SELECT u.id, u.name, o.total
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE u.active = true
AND o.created_at > :since
ORDER BY o.total DESC
LIMIT :limit
""";
// Use with JDBC or JPA:
Query q = em.createNativeQuery(query, UserOrderDto.class)
.setParameter("since", startDate)
.setParameter("limit", 100);
Compare this to the pre-Java-15 alternative of quote-and-concatenate — the text block is directly readable and diffable.
Rule of thumb: text blocks are especially valuable for SQL, where keyword alignment (SELECT/FROM/WHERE/ORDER BY) aids readability at a glance.
The compiler strips trailing whitespace from every line of a text block. This means spaces or tabs at the end of a content line are silently removed. This is usually desirable (cleaner output), but can surprise you if you intend to produce trailing spaces (e.g., in fixed-width formatted output).
String padded = """
item
total
""";
// Trailing spaces on each line are GONE:
// "item\ntotal\n"
Use \s to anchor a trailing space that must be preserved:
String padded = """
item \s
total \s
""";
// "item \ntotal \n" — one preserved trailing space per line
Rule of thumb: never rely on trailing spaces in text blocks; use
\s explicitly whenever a trailing space is meaningful.
Text blocks eliminate the visual noise of escaping quotes in HTML attributes:
String html = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>%s</title>
</head>
<body>
<h1>%s</h1>
</body>
</html>
""".formatted(title, heading);
Previously every " inside the HTML needed escaping as \", making
attributes like lang="en" look like lang=\"en\" — difficult to read
and error-prone to edit.
Rule of thumb: if your string contains " characters (HTML, JSON,
SQL string literals), a text block eliminates escape clutter entirely.
Java 15 also added String.indent(int n) which adjusts the indentation
of each line in a string by n spaces (positive = add, negative = remove):
String block = """
line1
line2
""";
// Add 4 spaces of indentation to every line:
System.out.print(block.indent(4));
// line1
// line2
// ← trailing newline preserved
// Remove spaces (clamped at 0 per line):
System.out.print(block.indent(-2));
String.stripIndent() (also Java 15) performs the same incidental
whitespace removal the compiler does, useful for text blocks received
from external sources at runtime.
Rule of thumb: use indent() for post-processing indentation;
use stripIndent() to clean up dynamically loaded multi-line strings
the same way the compiler cleans text block literals.
Text blocks were introduced as a preview feature in Java 13 (JEP 355)
and Java 14 (JEP 368), then finalized as a standard feature in
Java 15 (JEP 378). No --enable-preview flag is needed in Java 15+.
// Java 13/14 — required --enable-preview at compile and runtime
// Java 15+ — standard feature, no flag needed
String query = """
SELECT *
FROM orders
""";
Rule of thumb: text blocks are available unconditionally in Java 15+; if your codebase targets Java 15 or higher you should use them freely for all multi-line string content.
More Modern Java interview questions
More ways to practice
The self-quiz is live. Get notified when mock interviews and new question packs drop.