
In diesem Artikel erfährst du:
- Wie sollten String Templates das Zusammensetzen von Strings aus Text, Variablen und berechneten Werten vereinfachen?
- Was ist ein Template Processor, und welche gab es?
- Warum wurden String Templates wieder entfernt?
- Was nutzt du heute stattdessen?
String Templates wurden in Java 21 im Rahmen von Project Amber als Preview-Feature eingeführt. In Java 22 wurden sie ohne Änderungen in eine zweite Preview-Runde geschickt. Eine dritte Runde gab es nicht.
Status Quo der String-Verkettung
Um Strings zur Laufzeit anhand von Variablen und berechneten Werten zusammenzusetzen, gibt es verschiedene Möglichkeiten. Die geläufigsten sind die folgenden:
int a = ...;
int b = ...;
String concatenated = a + " times " + b + " = " + a * b;
String format = String.format("%d times %d = %d", a, b, a * b);
String formatted = "%d times %d = %d".formatted(a, b, a * b);
Oft wird auch ein StringBuilder, weniger oft java.text.MessageFormat eingesetzt. Aber bei keiner dieser Varianten siehst du dem Code auf einen Blick an, wie der fertige String aussieht.
String-Interpolation mit String Templates
Nahezu jede moderne Programmiersprache bietet String-Interpolation, d. h., sie wertet Platzhalter in einem String aus und ersetzt sie durch das Ergebnis.
Genau das (und noch mehr, s. u.) ermöglichten die durch JDK Enhancement Proposal 430 eingeführten „String Templates“.
Damit ließ sich das Beispiel von oben so umschreiben:
int a = ...;
int b = ...;
String interpolated = STR."\{a} times \{b} = \{a * b}";
Zur Laufzeit wurde der Platzhalter \{a} durch den Wert der Variablen a ersetzt und der Platzhalter \{b} durch den Wert der Variablen b.
Die durch \{...} gekennzeichneten Platzhalter durften nicht nur Variablen und arithmetische Ausdrücke enthalten, sondern jeden beliebigen Java-Ausdruck, z. B. einen statischen Methodenaufruf:
String interpolated = STR."\{a} times \{b} = \{Math.multiplyExact(a, b)}";
Der Platzhalter durfte auch Anführungszeichen enthalten, und der Übersicht halber konntest du ihn auf mehrere Zeilen aufteilen und mit Kommentaren versehen:
String dateMessage = STR."Today's date: \{
LocalDate.now().format(
// alternativ ginge auch DateTimeFormatter.ISO_DATE
DateTimeFormatter.ofPattern("yyyy-MM-dd")
)}";
String Templates ließen sich auch mit Text-Blöcken kombinieren:
int httpStatus = ...;
String errorMessage = ...;
String json = STR."""
{
"httpStatus": \{httpStatus},
"errorMessage": "\{errorMessage}"
}""";
Falls du dich gefragt hast, was das STR. vor den Strings zu bedeuten hat – die Antwort findest du im nächsten Abschnitt.
String Template Processor
STR ist der Name eines sogenannten Template Processors. Ein Template Processor definiert, wie Template-Text und Platzhalter zu einem Ergebnis zusammengesetzt werden. Das JDK brachte drei solcher Processors mit: STR, FMT und RAW.
STR Template Processor
Der STR-Processor wertet – wie oben beschrieben – die Java-Ausdrücke in den Platzhaltern aus und ersetzt die Platzhalter durch die dabei herauskommenden Werte.
STR ist eine Konstante vom Typ StringTemplate.Processor, die automatisch in jede Java-Datei importiert wird. Deshalb funktionierten die Beispiele oben ohne import-Anweisung.
FMT Template Processor
Ein weiterer Standard-Processor ist FMT. Er wertet Formatangaben aus, die vor den Platzhaltern stehen – wie wir sie von String.format() kennen. Anders als STR musst du ihn importieren, er liegt in der Klasse java.util.FormatProcessor.
Hier noch einmal unser Multiplikationsbeispiel mit Fließkommazahlen, die mit dem FMT-Processor auf zwei Stellen nach dem Komma gerundet werden:
import static java.util.FormatProcessor.FMT;
double a = ...;
double b = ...;
String interpolated = FMT."%.2f\{a} times %.2f\{b} = %.2f\{a * b}";
RAW Template Processor
Der dritte Standard-Processor ist RAW. Er setzt nichts zusammen, sondern liefert das StringTemplate-Objekt selbst zurück – die Textfragmente und die Werte der Platzhalter getrennt voneinander. Wie FMT musst du ihn importieren:
import static java.lang.StringTemplate.RAW;
int a = ...;
int b = ...;
StringTemplate template = RAW."\{a} times \{b} = \{a * b}";
List<String> fragments = template.fragments(); // liefert "", " times ", " = ", ""
List<Object> values = template.values(); // liefert a, b, a * b
Genau diese Trennung bekommt jeder Template Processor zu sehen: Er erhält Fragmente und Werte getrennt und entscheidet, was daraus wird – STR setzt sie zu einem String zusammen, FMT wertet dabei Formatangaben aus, und ein eigener Processor kann etwas ganz anderes zurückliefern, z. B. ein PreparedStatement.
Das folgende Diagramm zeigt diese drei Wege. Einen eigenen Processor, der SQL-Abfragen baut, beschreibt der nächste Abschnitt.
SQL Template Processor
Wie RAW zeigt, muss ein Template Processor keinen String zurückliefern. So könnte z. B. ein Template Processor implementiert werden, der SQL-Kommandos zusammenstellt und ein PreparedStatement zurückliefert – mit dem Suchbegriff als Parameter statt als Teil des SQL-Textes. Das schützt vor Injektionsangriffen:
String searchQuery = ...;
PreparedStatement statement = SQL."""
SELECT * FROM User u
WHERE u.userName LIKE '%\{searchQuery}%'""";
Ein solcher Processor war nie Teil des JDK. Er steht in JEP 459 als Beispiel dafür, was mit eigenen Processors möglich gewesen wäre – dort heißt er DB, fügt die Fragmente mit ? zu einer Abfrage zusammen und setzt die Werte als Parameter des PreparedStatement. Wie du einen eigenen Processor geschrieben hättest, steht dort ebenfalls.
Warum wurden String Templates zurückgezogen?
Nach der zweiten Preview-Runde zog Brian Goetz am 8. März 2024 auf der Mailingliste amber-spec-experts Bilanz. An den Zielen hielt er fest: lesbare Strings aus Text und Ausdrücken, Schutz vor Injektionsangriffen, Ergebnisse, die keine Strings sind. Auch die Platzhalter-Syntax \{...} stand nicht zur Debatte.
Zur Debatte stand der Template Processor. Beim Einsatz von String Templates in jextract (dem Tool, das aus den Header-Dateien einer C-Bibliothek Java-Code für die Foreign Function & Memory API erzeugt) hatten die JDK-Entwickler:innen festgestellt, dass ein Processor nur eine neue Schreibweise für einen Methodenaufruf ist. Statt DB."..." könnte genauso gut Query.of("...") dastehen – und Methoden hat Java schon.
Dass Template und Processor in einem Ausdruck stecken, war für Goetz der Kern des Problems: API-Designer:innen mussten sich entscheiden, ob sie einen Processor oder eine gewöhnliche Methode schreiben – oft, bevor die Folgen absehbar waren. Dabei vereint DB."..." zwei Schritte:
- Java wertet das Template aus: Es zerlegt den Text in die Fragmente und berechnet die Werte der Platzhalter.
- Ein Processor macht aus Fragmenten und Werten das Ergebnis – einen String, einen formatierten String oder eine Datenbankabfrage.
Diese beiden Schritte wollte Goetz trennen. Den ersten übernähme ein neues Literal: "Hello \{name}" wäre ohne vorangestelltes STR. oder DB. bereits ein StringTemplate-Objekt. Den zweiten übernähme die Methode, an die du dieses Objekt übergibst. System.out.println("Hello \{name}") etwa würde eine neue Überladung println(StringTemplate) aufrufen, die das Template zu einem String zusammensetzt; eine Datenbank-Bibliothek könnte Query.of(StringTemplate) anbieten und die Werte als Parameter setzen.
Vier Wochen später, am 5. April 2024, zog Gavin Bierman die Konsequenz: Es gab Zustimmung dafür, das Design zu ändern, aber keinen Konsens darüber, wie. Also kam das Feature nicht in Java 23, auch nicht als Preview: Die JDK-Entwickler:innen entfernten es vollständig aus Compiler und Klassenbibliothek (JDK-8329948); zwei übrig gebliebene Hilfsmethoden in AbstractStringBuilder verschwanden mit Java 26 (JDK-8371130). Der JEP für die geplante dritte Preview-Runde, JEP 465, ist zurückgezogen.
Wie geht es weiter? Einen Nachfolge-JEP gibt es bis heute nicht (Stand: Oktober 2026, Java 27). Auf der Mailingliste amber-dev wurde im Juli und August 2025 erneut über die Platzhalter-Syntax diskutiert; Ron Pressler sprach dort von laufenden „design explorations“.
Was kannst du heute statt String Templates nutzen?
Für Strings mit Platzhaltern empfehle ich String.formatted(), das es seit Java 15 gibt:
int a = ...;
int b = ...;
String result = "%d times %d = %d".formatted(a, b, a * b);
Das JSON-Beispiel von oben wird damit zu einem Text-Block mit formatted():
int httpStatus = ...;
String errorMessage = ...;
String json = """
{
"httpStatus": %d,
"errorMessage": "%s"
}""".formatted(httpStatus, errorMessage);
Das ist kaum länger als die Template-Variante – aber du musst selbst darauf achten, dass Anzahl und Reihenfolge der Argumente zu den Platzhaltern passen. Vertauschst du zwei Argumente, fällt das erst im Test auf, nicht beim Kompilieren.
Für die übrigen Fälle gibt es diese Mittel:
String.format()ist dieselbe Funktion als statische Methode.java.text.MessageFormatnummeriert die Platzhalter ({0},{1}) und formatiert Zahlen und Datumsangaben nach der Locale – für Texte, die in mehreren Sprachen ausgegeben werden.- Ein
StringBuilderpasst, wenn du einen String in einer Schleife zusammensetzt. - Für SQL nimmst du ein
PreparedStatementmit?-Platzhaltern. Das ist derselbe Schutz vor Injektionsangriffen, den derSQL-Processor geboten hätte – nur schreibst du die Parameter selbst.
Fazit
String Templates haben gezeigt, wie String-Interpolation in Java aussehen könnte – und die JDK-Entwickler:innen haben sie zurückgezogen, bevor das Design festgeschrieben war. Genau dafür sind Preview-Features da.
Daraus folgt für deinen Code: Preview-Features bleiben in Experimenten, nicht in Produktivcode. Und für Strings mit Platzhaltern bleibt formatted() bis auf Weiteres mein Mittel der Wahl.
Wenn dir der Artikel weitergeholfen hat, würde ich mich sehr über eine positive Bewertung auf meinem ProvenExpert-Profil freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.




