• Home
  • About
    • Thoughts To Pen photo

      Thoughts To Pen

      My thoughts on Computer Programming || Psychology || Personal Finances || & much more...

    • Learn More
    • Twitter
    • Instagram
    • Github
    • StackOverflow
  • Posts
    • All Posts
    • All Tags
  • Projects
  • Portfolio
  • Resources
  • About

Text Blocks (Java 17)

15 Nov 2025

Text Blocks, finalized in Java 15 and available in Java 17 through JEP 378, revolutionize how we work with multi-line strings in Java. Using triple-double quotes ("""), text blocks make it easy to write readable, maintainable strings for JSON, SQL, HTML, XML, and other multi-line content.

The Problem with Traditional Strings

Before text blocks, multi-line strings required extensive use of escape sequences and concatenation:

String json = "{\n" +
              "  \"name\": \"John Doe\",\n" +
              "  \"age\": 30,\n" +
              "  \"email\": \"john@example.com\"\n" +
              "}";

String sql = "SELECT users.name, users.email, orders.total\n" +
             "FROM users\n" +
             "JOIN orders ON users.id = orders.user_id\n" +
             "WHERE orders.status = 'completed'\n" +
             "ORDER BY orders.total DESC";

This approach is:

  • Hard to read: Escape sequences clutter the code
  • Error-prone: Easy to forget \n or closing quotes
  • Difficult to maintain: Formatting changes require updating multiple lines

Text Blocks to the Rescue

Text blocks use triple-double quotes and preserve formatting automatically:

String json = """
    {
      "name": "John Doe",
      "age": 30,
      "email": "john@example.com"
    }
    """;

String sql = """
    SELECT users.name, users.email, orders.total
    FROM users
    JOIN orders ON users.id = orders.user_id
    WHERE orders.status = 'completed'
    ORDER BY orders.total DESC
    """;

Much cleaner and more readable!

How Text Blocks Work

Basic Syntax

A text block starts with """ followed by a line terminator, and ends with """:

String greeting = """
    Hello,
    World!
    """;

Important: The opening """ must be followed by a line terminator. This is invalid:

String invalid = """Hello""";  // ✗ Compile error

Automatic Indentation Management

Text blocks automatically remove common leading whitespace:

public class Example {
    public void printMessage() {
        String message = """
            This is indented in the code,
            but the common indentation is removed
            from the final string.
            """;
        System.out.println(message);
    }
}

Output:

This is indented in the code,
but the common indentation is removed
from the final string.

The closing """ position determines the indentation baseline:

// Closing delimiter at the start - removes all indentation
String noIndent = """
    Line 1
    Line 2
    """;

// Closing delimiter indented - preserves relative indentation
String withIndent = """
    Line 1
    Line 2
        """;

Real-World Examples

1. JSON Configuration

public class ConfigGenerator {
    
    public String generateDatabaseConfig(String host, int port, String database) {
        return """
            {
              "database": {
                "host": "%s",
                "port": %d,
                "name": "%s",
                "pool": {
                  "minSize": 5,
                  "maxSize": 20,
                  "timeout": 30000
                }
              }
            }
            """.formatted(host, port, database);
    }
    
    public String generateUserJson(String name, String email, List<String> roles) {
        String rolesJson = roles.stream()
            .map(role -> "\"" + role + "\"")
            .collect(Collectors.joining(", "));
            
        return """
            {
              "user": {
                "name": "%s",
                "email": "%s",
                "roles": [%s],
                "active": true
              }
            }
            """.formatted(name, email, rolesJson);
    }
}

2. SQL Queries

public class UserRepository {
    
    public String getUsersWithOrdersQuery() {
        return """
            SELECT 
                u.id,
                u.name,
                u.email,
                COUNT(o.id) as order_count,
                SUM(o.total) as total_spent
            FROM users u
            LEFT JOIN orders o ON u.id = o.user_id
            WHERE u.active = true
            GROUP BY u.id, u.name, u.email
            HAVING COUNT(o.id) > 0
            ORDER BY total_spent DESC
            LIMIT 100
            """;
    }
    
    public String getComplexReportQuery(String startDate, String endDate) {
        return """
            WITH monthly_sales AS (
                SELECT 
                    DATE_TRUNC('month', order_date) as month,
                    SUM(total) as revenue
                FROM orders
                WHERE order_date BETWEEN '%s' AND '%s'
                GROUP BY month
            )
            SELECT 
                month,
                revenue,
                LAG(revenue) OVER (ORDER BY month) as prev_month_revenue,
                revenue - LAG(revenue) OVER (ORDER BY month) as growth
            FROM monthly_sales
            ORDER BY month DESC
            """.formatted(startDate, endDate);
    }
}

3. HTML Templates

public class EmailTemplateGenerator {
    
    public String generateWelcomeEmail(String userName, String activationLink) {
        return """
            <!DOCTYPE html>
            <html>
            <head>
                <style>
                    body { font-family: Arial, sans-serif; }
                    .container { max-width: 600px; margin: 0 auto; }
                    .button {
                        background-color: #4CAF50;
                        color: white;
                        padding: 15px 32px;
                        text-decoration: none;
                        display: inline-block;
                    }
                </style>
            </head>
            <body>
                <div class="container">
                    <h1>Welcome, %s!</h1>
                    <p>Thank you for joining our platform.</p>
                    <p>Please click the button below to activate your account:</p>
                    <a href="%s" class="button">Activate Account</a>
                    <p>If you didn't create this account, please ignore this email.</p>
                </div>
            </body>
            </html>
            """.formatted(userName, activationLink);
    }
}

4. XML Documents

public class XmlGenerator {
    
    public String generateProductXml(String id, String name, double price, List<String> categories) {
        String categoriesXml = categories.stream()
            .map(cat -> "        <category>" + cat + "</category>")
            .collect(Collectors.joining("\n"));
            
        return """
            <?xml version="1.0" encoding="UTF-8"?>
            <product>
                <id>%s</id>
                <name>%s</name>
                <price currency="USD">%.2f</price>
                <categories>
            %s
                </categories>
            </product>
            """.formatted(id, name, price, categoriesXml);
    }
}

String Interpolation with formatted()

Text blocks work seamlessly with the formatted() method (or String.format()):

String name = "Alice";
int age = 30;

String message = """
    User Profile:
    -------------
    Name: %s
    Age: %d
    Status: %s
    """.formatted(name, age, age >= 18 ? "Adult" : "Minor");

Escape Sequences Still Work

You can still use escape sequences when needed:

String withEscapes = """
    Line 1\tTabbed
    Line 2\t\tDouble tabbed
    Quote: \"Hello\"
    Backslash: \\
    """;

Preserving Trailing Whitespace

Use \s to preserve trailing spaces:

String withTrailingSpace = """
    This line has trailing space\s
    This line doesn't
    """;

Line Continuation

Use \ at the end of a line to join it with the next:

String oneLine = """
    This is all \
    one \
    line.
    """;
// Result: "This is all one line."

Best Practices

1. Position the Closing Delimiter Carefully

// Good - closing delimiter determines baseline indentation
String good = """
    Content here
    More content
    """;

// Also good - explicit about no indentation
String alsoGood = """
Content here
More content
""";

2. Use for Multi-Line Content Only

// Don't use text blocks for single-line strings
String bad = """
    Just one line
    """;

// Use regular strings instead
String good = "Just one line";

3. Combine with String Methods

String template = """
    {
      "name": "%s",
      "value": %d
    }
    """;

String json = template.formatted("example", 42)
                      .trim()
                      .replaceAll("\\s+", " ");

Conclusion

Text Blocks are a game-changer for working with multi-line strings in Java. They make code more readable, reduce errors, and simplify maintenance. Whether you’re working with JSON, SQL, HTML, or any other multi-line format, text blocks provide a clean, intuitive syntax that feels natural and keeps your code organized.



programmingjavajava17 Share Tweet Msg