Contents
- Syntax and Basic Usage
- Indentation Stripping
- New Escape Sequences
- Practical Examples: SQL, JSON, HTML
- String Methods for Text Blocks
A text block opens with """ followed by a newline (the opening delimiter cannot be on the same line as content) and closes with """ on any line.
// Before text blocks — messy escape-heavy string
String json = "{\n" +
" \"name\": \"Alice\",\n" +
" \"age\": 30\n" +
"}";
// With text block — clean and readable
String json = """
{
"name": "Alice",
"age": 30
}
""";
// Both produce the same string value
System.out.println(json);
// {
// "name": "Alice",
// "age": 30
// }
// Text blocks are regular String objects — all String methods work
System.out.println(json.getClass()); // class java.lang.String
System.out.println(json.contains("Alice")); // true
The opening """ must be followed immediately by a line break. Putting content on the same line as the opening delimiter is a compile error.
Java automatically strips incidental whitespace — leading spaces that exist only because of code indentation, not because they are part of the string content. The algorithm looks at the closing """ and strips the same number of leading spaces from every line.
class MyClass {
String query = """
SELECT id, name
FROM users
WHERE active = true
""";
// The 12 spaces of indentation before SELECT are "incidental"
// and are stripped. The result is:
// "SELECT id, name\nFROM users\nWHERE active = true\n"
}
// Position of closing """ controls indentation stripping:
// 1. Closing """ at column 0 — strips minimum indentation
String a = """
line 1
line 2
""";
// Result: " line 1\n line 2\n" (4-space indent preserved)
// 2. Closing """ indented — strips more leading whitespace
String b = """
line 1
line 2
""";
// Result: "line 1\nline 2\n" (4 spaces stripped by closing """)
// Trailing newline: if closing """ is on its own line, there IS a trailing \n
// To suppress trailing newline, put closing """ right after last content:
String noTrailing = """
hello"""; // "hello" — no trailing newline
Text blocks always use \n (LF) as the line separator, regardless of the platform's line separator. This ensures consistent behavior across operating systems.
Java 15 introduced two new escape sequences specifically for use in text blocks:
- \ (backslash at end of line) — line continuation: joins lines without inserting a newline. Useful for very long strings that you want to wrap visually but keep on one logical line.
- \s — explicit space: inserts a space character and also prevents trailing whitespace trimming on that line.
// Line continuation — \ at end of line suppresses the newline
String longUrl = """
https://example.com/api/v1/\
users?status=active&page=1\
""";
// Result: "https://example.com/api/v1/users?status=active&page=1"
// (no newlines, despite the multi-line source)
// \s preserves trailing whitespace (useful in fixed-width formats)
String padded = """
red \s
green\s
blue \s
""";
// Each line ends with exactly 2 spaces (the literal space + \s)
// Standard escapes still work in text blocks
String withQuotes = """
She said \"hello\" to everyone.
He replied: it\'s fine.
""";
Text blocks eliminate the escaping and concatenation noise that made multi-line string literals painful before Java 15. SQL queries, JSON payloads, HTML templates, and XML configurations become readable inline without backslash-n sequences or string concatenation on every line. Indentation is stripped based on the closing delimiter position — placing """ at the level of the content removes the code-level indent entirely. The underlying mechanisms are stripIndent() (available as a String method for runtime use) and translateEscapes(). Combine with formatted() to plug in dynamic values.
// SQL query — readable, no escape clutter
String sql = """
SELECT u.id, u.username, 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.created_at DESC
LIMIT :limit
""";
// JSON payload for HTTP request
String requestBody = """
{
"event": "user.signup",
"data": {
"username": "%s",
"email": "%s",
"plan": "free"
}
}
""".formatted(username, email);
// HTML email template
String html = """
<!DOCTYPE html>
<html>
<body>
<h1>Welcome, %s!</h1>
<p>Your account is ready. <a href="%s">Click here</a> to get started.</p>
</body>
</html>
""".formatted(name, loginUrl);
// XML config
String config = """
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<server port="8080" host="0.0.0.0"/>
<database url="jdbc:postgresql://localhost/mydb"/>
</configuration>
""";
Several String methods are particularly useful with text blocks:
// formatted() — text block version of String.format()
String greeting = """
Hello, %s!
Your score is %d out of %d (%.1f%%).
""".formatted("Alice", 95, 100, 95.0);
// stripIndent() — programmatically strip incidental indent from a runtime string
String runtime = " line1\n line2\n line3\n";
System.out.println(runtime.stripIndent());
// line1
// line2
// line3
// translateEscapes() — interpret escape sequences in a runtime string
String withEscapes = "Hello\\nWorld"; // literal backslash-n
System.out.println(withEscapes.translateEscapes()); // Hello
// World
// indent(n) — add or remove leading whitespace from each line
String indented = "line1\nline2\n".indent(4);
// " line1\n line2\n"
String dedented = " line1\n line2\n".indent(-2);
// " line1\n line2\n"
Text blocks are a pure syntax feature — at runtime they are ordinary String objects. There is no performance difference from equivalent string concatenation at runtime.