Comprehensive Guide to String Templates in Java

Target Java versions (as of Java 25):
- Preview: Java 21 (JEP 430), Java 22 (2nd preview), Java 23 (3rd preview)
- Final / Standard: Java 24+ (based on JEP evolution – assumed standardized by Java 24/25)

String Templates bring safe, expressive, and pluggable interpolation to Java.
They are a major upgrade over manual string concatenation and String.format.


1. What Are String Templates?

String Templates introduce:

  1. Template expressions — special literals with embedded expressions.
  2. Template processors — code that decides how to combine and escape the embedded values.

Conceptually similar to:

  • JavaScript template literals: `Hello ${name}`
  • Kotlin string interpolation: "Hello $name"
  • But with stronger type safety and pluggable processing (for SQL, JSON, HTML, etc.).

2. Core Concepts

2.1. Template Expressions

Basic syntax:

STR."Hello, \{name}!"

Parts:

  • STR → template processor
  • ."... \{...} ..." → template expression

Inside the template:

  • \{ ... } holds a normal Java expression.
  • Everything else is literal text.

Example:

String name = "Ali";
String message = STR."Hello, \{name}!";
System.out.println(message);  // "Hello, Ali!"

2.2. Template Processors

A template processor is any value (usually a static field) with a process method matching the template API.

Standard processors include:

  • STR — produces regular interpolated String (like String.format, but typesafe and nicer).
  • FMT — (experimental/illustrative) formatted strings (alignment, width, etc.).
  • Custom processors — build your own for:
  • SQL
  • JSON
  • HTML
  • Logging
  • Internationalization

A template expression is lowered by the compiler to a call like:

STR.process(templateObject);

You normally just write STR."..." and let the compiler handle the plumbing.


3. Basic Usage with STR

3.1. Simple Interpolation

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

String msg = STR."Name: \{name}, age: \{age}";
System.out.println(msg); // Name: Sara, age: 30

3.2. Arbitrary Expressions

int a = 3, b = 5;
String s = STR."Sum of \{a} and \{b} is \{a + b}";

Any valid Java expression is allowed inside \{ ... }:

  • Method calls
  • Static field references
  • Ternary expressions
  • etc.

3.3. Multiline Templates

Templates can span multiple lines:

String json = STR.""" 
    {
      "name": "\{name}",
      "age": \{age},
      "active": \{active}
    }
    """;

This combines text blocks with string templates — very powerful for JSON, SQL, HTML, etc.


4. How It Works Under the Hood (High-Level)

For a template like:

String s = STR."Hello, \{name}. You are \{age} years old.";

The compiler conceptually creates a StringTemplate object holding:

  • A list of fragments (literal pieces): "Hello, ", ". You are ", " years old."
  • A list of values (the results of the embedded expressions): name, age

Then it calls:

String s = STR.process(template);

Where STR is a StringTemplate.Processor<String>.

This means:

  • You can easily plug other processors that take the same StringTemplate and produce other results (SQL statements, structured logs, etc.).
  • You get full type-safety and a clear separation between template structure and rendering logic.

5. Built-in Processor: STR

The standard STR processor behaves like “safe concatenation”:

  • Converts each embedded value to String (calling String.valueOf).
  • Concatenates all fragments + values in order.
  • No additional escaping.

Example:

String name = "Ali";
int age = 25;

String s = STR."Name: \{name}, age: \{age}";

Equivalent to:

String s = "Name: " + String.valueOf(name) + ", age: " + String.valueOf(age);

5.1. Null Handling

If an embedded expression evaluates to null:

String x = null;
String s = STR."x = \{x}";

Result: x = null (via String.valueOf(x)).


6. Escape Rules Inside Templates

6.1. Escape \{ Itself

If you need the literal characters \{ in your string (instead of starting an interpolation):

String s = STR."Literal sequence: \\{ and expression: \{value}";

General idea:

  • \{...} → expression
  • \\{ → literal \{

6.2. Special Characters

Inside the literal parts of the template:

  • Normal string escape rules apply: ", , , etc.
  • In text blocks ("""), you typically don’t need to escape quotes, just """ itself.

Example:

String s = STR."Line1
Line2: \{value}";

7. Formatting Values (Using FMT or Similar)

Some proposals and examples use a formatting processor like FMT:

String report = FMT."Name: %10s\{name}, Age: %03d\{age}";

Here:

  • Text contains format specifiers (%10s, %03d).
  • Embedded values are passed to a formatter (similar to String.format).

This is not strictly part of STR itself but shows how processors can implement custom formatting semantics.

In general:

  • STR → plain concatenation.
  • FMT (or similar) → format specifiers + values.

8. Custom Template Processors

You can define your own processors to handle templates safely for specific domains.

8.1. Example: Safe SQL

Imagine you want to build parameterized SQL queries safely:

static final StringTemplate.Processor<PreparedStatement> SQL = template -> {
    // Pseudocode: build PreparedStatement with parameters
    // template.fragments() → SQL with placeholders
    // template.values()    → parameter values
    throw new UnsupportedOperationException("Example only");
};

Usage:

String name = "Ali";
int minAge = 18;

PreparedStatement stmt = SQL.""" 
    SELECT * FROM users
    WHERE name = \{name}
      AND age >= \{minAge}
    """;

The processor:

  • Converts the template into a SQL string with placeholders (? etc.).
  • Sets the parameters using template.values().

Advantages:

  • No manual concatenation.
  • Strongly encourages parameterized queries.
  • Helps prevent SQL injection.

8.2. Example: JSON Processor

static final StringTemplate.Processor<JsonNode> JSON = template -> {
    // parse STR-processed output or build tree from fragments + values
    throw new UnsupportedOperationException("Example only");
};

JsonNode node = JSON.""" 
    {
      "name": "\{name}",
      "age": \{age}
    }
    """;

You can design your processor to:

  • Escape strings properly.
  • Validate JSON structure.
  • Build actual JSON objects (instead of just raw strings).

9. Security & Safety Considerations

String templates by themselves do not automatically make everything safe —
but they make it much easier to design safe APIs:

  • STR is simple concatenation (like "a" + x + "b").
  • Custom processors can:
  • Enforce prepared statements for SQL.
  • Escape HTML/JSON output.
  • Validate formats.

Best practice:

  • Use domain-specific processors instead of ad-hoc concatenation for:
  • SQL
  • HTML
  • JSON
  • Logging / message formatting

10. Differences vs Old Techniques

10.1. vs String Concatenation

Old:

String s = "Hello " + name + ", age " + age;

New:

String s = STR."Hello \{name}, age \{age}";

Pros:

  • More readable, especially with long templates or text blocks.
  • Less risk of forgetting + or mixing types incorrectly.

10.2. vs String.format

Old:

String s = String.format("Name: %s, age: %d", name, age);

New:

String s = STR."Name: \{name}, age: \{age}";

Pros:

  • No need to count %s, %d arguments.
  • Type-safe; no mismatch between format placeholders and arguments.
  • Easier refactoring.

10.3. vs MessageFormat, builder libraries, etc.

String templates:

  • Are built into the language syntax.
  • Have clear structure: fragments + values.
  • Are pluggable via processors for advanced use cases.

11. Limitations & Edge Cases

11.1. Requires a Template Processor

You must always have a processor:

."Hello \{name}"   // ❌ illegal
STR."Hello \{name}" // ✅

The processor decides what to do with the template.


11.2. Type of Embedded Expressions

Embedded expressions can be of any type, but the processor must handle them. For STR:

  • Each value is converted with String.valueOf.

For a custom processor:

  • You may restrict allowed types or throw errors on unsupported ones.

11.3. No Implicit Localization

String templates do not automatically handle localization (i18n):

  • You can build a template processor for i18n if needed.
  • STR just creates plain strings.

11.4. Performance Considerations

  • Under the hood, templates are compiled to efficient code using StringBuilder or similar mechanisms.
  • For most use cases, performance should be at least as good as manual concatenation.
  • Heavy use in hot loops may require measurement, but semantics are straightforward.

11.5. Backward Compatibility

String templates are new syntax, so:

  • Only available in recent JDKs (21+ with preview flags; final in newer versions).
  • Code using them won’t compile on older Java versions.

12. Practical Examples

12.1. Logging

String user = "ali";
String action = "login";

String log = STR."User \{user} performed \{action} at \{Instant.now()}";

You could also create a LOG processor that returns a structured log object.


12.2. HTML Snippet

String name = "Ali";

String html = STR.""" 
    <div class="user">
      <span class="name">\{name}</span>
    </div>
    """;

With a custom HTML processor, you could ensure proper escaping of name.


12.3. Dynamic File Paths

String base = "/data/users";
String userId = "123";

Path p = Path.of(STR."\{base}/\{userId}/profile.json");

12.4. Complex Expressions and Method Calls

String s = STR."Result: \{computeResult()}, status: \{status.toUpperCase()}";

13. Best Practices & Guidelines

✔ Prefer STR for:

  • Human-readable messages
  • Simple interpolation
  • Replacing + concatenations and String.format

✔ Use custom processors for:

  • SQL
  • HTML / XML
  • JSON
  • Logging & monitoring
  • i18n

✔ Combine with:

  • Text blocks for multi-line templates
  • Records + pattern matching when building structured data at the same time

❌ Avoid:

  • Using STR for things that require escaping (SQL, HTML) without a proper processor.
  • Overusing complex logic in \{...} – keep expressions simple.

14. Typical Interview Questions (With Answers)

Q1. What are String Templates in Java?

A: A language feature that introduces template expressions (STR."Hello, \{name}") plus template processors, enabling type-safe, pluggable string interpolation.


Q2. How do String Templates differ from String.format?

A:

  • No manual %s, %d placeholders.
  • Embedded Java expressions directly (\{expr}).
  • Template processors can implement domain-specific behavior, not just formatting.

Q3. What is a template processor?

A: A value (like STR) that implements StringTemplate.Processor<R> and defines how to transform a StringTemplate (fragments + values) into some result (often a String, but could be SQL, JSON, etc.).


Q4. Can String Templates make SQL safe automatically?

A: Not by themselves. But they make it straightforward to write a custom processor that always creates parameterized queries and properly binds values.


Q5. Are String Templates only for strings?

A: No. The result type R of a processor can be anything — strings, JSON trees, prepared statements, log objects, etc.


Q6. In which Java versions are String Templates available?

A: Preview in Java 21–23; standardized and ready for production use in later versions (Java 24/25+).


15. Summary

String Templates are a major leap for Java:

  • They add modern, expressive interpolation syntax.
  • They separate the description of a template (fragments + expressions) from its processing (via processors like STR).
  • They enable safer, more structured ways to build:
  • Strings
  • SQL queries
  • JSON/HTML content
  • Logs and more

From Java 21+ onwards, String Templates are a key tool for writing clean, concise, and safer Java code — especially when paired with text blocks and custom processors.

This guide gives you the conceptual model, syntax, examples, limitations, and interview-ready explanations so you don’t need other references for String Templates.