StringSubstitutor from Apache Commons Text library is a lightweight way of doing this, provided your values are already formatted correctly.

Map<String, String> values = new HashMap<>();
values.put("value", "1");
values.put("column","2");

StringSubstitutor sub = new StringSubstitutor(values, "%(", ")");
String result = sub.replace("There's an incorrect value '%(value)' in column # %(column)");

The result string will contain the following:

There's an incorrect value '1' in column # 2

When using Maven you can add this dependency to your pom.xml:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.10.0</version>
</dependency>
Answer from schup on Stack Overflow
🌐
Baeldung
baeldung.com › home › java › java string › named placeholders in string formatting
Named Placeholders in String Formatting | Baeldung
August 27, 2025 - Java standard library provides the String.format() method to format a template-based string, such as String.format(“%s is awesome”, “Java”). In this tutorial, we’ll explore how to make string formatting support named parameters.
🌐
Reddit
reddit.com › r/learnprogramming › string template with named placeholders
r/learnprogramming on Reddit: String template with named placeholders
July 14, 2022 -

Imagine the following piece of code

Template("Hello {name}, you are {position} in line").format(name="Alice", position=12, extra=42) 

Would you rather that an error be thrown due to an unbound key (extra) being passed or should it be ignored?

I didn't find much languages even having such string templating built in except other than Python (string.format) and Rust (format!), in Python the extra key/value is ignored, while Rust will throw an exception.

What would be your approach?

Top answer
1 of 2
1
Thanks for all responses, please note, My question was specifically for named placeholders not positional, and I am looking for a template system, i.e. something to be able to reuse and plug in different values, not for an interpolated string where the variables have to be predefined in scope
2 of 2
1
There are 'format strings' in many languages... eg. Java "Hello %s, you are %d in line".formatted("Alice", 12, 42) I think many languages silently ignore the unbound param (though many IDE's can report it) - since the params list might not be dynamic (that is it may be a literal param list in the code as opposed to data), but the formatting template could be dynamic. An alternative is String Interpolation, which is available in many languages. Java, which lacks it, is investigating adding the feature - from their feature proposal we can see the following: Language | Example | JavaScript | ${x} plus ${y} equals ${x + y} (uses backticks) | C# | $"{x} plus {y} equals {x + y}" | Visual Basic | $"{x} plus {y} equals {x + y}" | Scala | f"$x%d plus $y%d equals ${x + y}%d" | Python | f"{x} plus {y} equals {x + y}" | Ruby | "#{x} plus #{y} equals #{x + y}" | Groovy | "$x plus $y equals ${x + y}" | Kotlin | "$x plus $y equals ${x + y}" | Swift | "(x) plus (y) equals (x + y)" I think Rust would be something like format!("{} plus {} equals {}", x, y, x + y) or format!("{x} plus {y} equals {}", x + y) The types of expressions and formatting specifiers that can be embedded in the template itself vary a lot by language. Java is proposing something like STR."\{x} + \{y} = \{x + y}" The STR. prefix exists because the feature is expandable to include other consumers of the template that might want to do different enforcement / checking and produce a type other than a String - eg an SQL processor validating/escaping the SQL, and generating an SQL request with the expressions as SQL params instead of literals. In many cases, a benefit of interpolation is not just readability/brevity, but also that the validation is a compile-time exercise and I expect most compile-time languages would expect unbound params or values to be a compile-time error. Edit: Actually include the String Template proposal link.
🌐
Blogger
techtots.blogspot.com › 2013 › 07 › java-message-format-using-named.html
Tech Tots: Java Message Format Using Named Placeholder
The Java MessageFormat class allows user to pre-define a string with placeholders and then fill the placeholders with actual strings later to construct a proper message. It's all fine if you're used to numbered placeholders e.g. {0} and {1}. Since I'm used to Drupal's format_string() function, ...
🌐
HappyCoders.eu
happycoders.eu › java › string-templates
String Templates in Java
June 12, 2025 - STR is the name of a so-called template processor (more precisely: a constant of type StringTemplate.Processor automatically imported into every Java file). A template processor defines how template text and placeholders are combined.
🌐
Medium
bijukunjummen.medium.com › java-string-templates-50fbdc9b2fb7
Java String Templates. The first time you look at a Java… | by Biju Kunjummen | Medium
December 21, 2023 - The first time you look at a Java String Template, it feels right and wrong simultaneously. String first = "John"; String last = "Smith"; String info = STR. "My first name is \{ first } and my last name is \{ last }" ; Right because the result of the final statement is with the placeholders correctly evaluated and filled in.
🌐
Baeldung
baeldung.com › home › java › java string › string templates in java
String Templates in Java | Baeldung
July 7, 2025 - The base template string remains static. However, the order and number of arguments passed here are crucial for the correctness of its response. Java provides a MessageFormat class of the Java.text package that helps in the composition of text messages with placeholders for dynamic data.
Find elsewhere
🌐
CodingTechRoom
codingtechroom.com › tutorial › java-mastering-java-string-formatting-with-named-placeholders
Java String Formatting with Named Placeholders: A Comprehensive Guide - CodingTechRoom
Solution: Always ensure that the Map keys match the placeholder names in your template string. Mistake: Not handling `null` values in the map can lead to NullPointerException. Solution: Check for null values before replacement and provide a default value if necessary. Named placeholders offer significant advantages in string formatting, particularly in terms of code maintainability and readability. While Java doesn’t natively support this feature, using a Map to replace placeholders allows developers to mimic this behavior effectively.
🌐
OpenJDK
openjdk.org › jeps › 430
JEP 430: String Templates (Preview)
September 17, 2021 - This version of the processor throws ... method StringTemplate.Processor::of. Instead, we use a lambda expression on the right-hand side directly. In turn, this means we cannot use var on the left-hand side because Java requires an explicit target type for the lambda expression. To make it more efficient, we could memoize this processor by compiling the template's fragments into a JSONObject with placeholder values and ...
🌐
GitHub
google.github.io › mug › apidocs › com › google › mu › util › StringFormat.html
StringFormat (mug-root 9.6-SNAPSHOT API)
Compared to equivalent String.format("%s=%s", foo, bar), using named placeholders works better if the template strings are public constants that are used across multiple classes. The compile-time placeholder name check helps to ensure that the arguments are passed correctly. Among the different formatting APIs, in the order of efficiency (fastest first): ... StringFormat.using(...) and String.format(...) in Java 21.
🌐
OpenJDK
openjdk.org › jeps › 459
JEP 459: String Templates (Second Preview)
August 14, 2023 - The ability to use a string literal or a text block as a template argument improves the flexibility of template expressions. Developers can write template expressions that initially have placeholder text in a string literal, such as
🌐
Belief Driven Design
belief-driven-design.com › looking-at-java-21-string-templates-c7cbc
Looking at Java 21: String Templates | belief driven design
June 20, 2023 - The new way to work with Strings in Java is called template expression, a programmable way of safely interpolating expressions in String literals. And even better than just interpolating, we can turn structured text into any object, not just a String. The create a template expression, we need two things: ... These two requirements are combined by a dot, almost like a method call. Using one of the previous examples, it looks like this: ... var name = "Ben"; var tempC = 28; var greeting = STR."Hello \{this.user.firstname()}, how are you?\nIt's \{tempC}°C today!";
🌐
DZone
dzone.com › data engineering › data › a clarified string formatting cheatsheet
A Clarified String Formatting Cheatsheet
September 22, 2017 - It can contain both String literal information that isn’t associated with any arguments and argument-specific formatting data. Formatting data will always start with a percent sign (%) followed by the formatting semantics. Let’s look at some examples. Let’s start with the simplest example. In the code snippet below the placeholder, %s is replaced by the name Alex.
🌐
Scaler
scaler.com › home › topics › java string interpolation
Java String Interpolation - Scaler Topics
December 20, 2022 - Here we can observe that the "My name is " part of the string is repetitive and the part that is changing is the last word. Thus the changing portion of the string (the last word in this case) can be replaced by a placeholder that will contain values according to the input. Thus in Java, we can write the string in the form:
🌐
Linux Hint
linuxhint.com › java-string-formatting
Java String Formatting
Linux Hint LLC, [email protected] 1210 Kelly Park Circle, Morgan Hill, CA 95037 Privacy Policy and Terms of Use
🌐
GeeksforGeeks
geeksforgeeks.org › java › java-program-to-illustrate-string-interpolation
String Interpolation in Java - GeeksforGeeks
July 23, 2025 - The String format() method in Java uses placeholders, for example, "%s" to insert variable values into a string, with the variables provided as additional arguments after the format string.
Top answer
1 of 1
6

Performing string substitutions using multiple passes is almost always the wrong approach, and leads to bugs. If one of the values happens to be a string that looks like a %(key), then all sorts of unpredictable things could happen, including various uncontrolled format string attacks!

Therefore, the string replacements must be done in a single pass of the format string. I recommend doing it using a regular expression.

Furthermore, your method provides no escape mechanism, in case you need to specify a literal %(blah) in the format string. In Java, it would be customary to use backslash as an escape character.

Suggested solution

This solution uses Matcher.replaceAll(Function<MatchResult,String> replacer), which was introduced in Java 9, to provide each substitution text via a callback.

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NamedFormatter {
    private static final Pattern RE = Pattern.compile(
        "\\\\(.)" +         // Treat any character after a backslash literally 
        "|" +
        "(%\\(([^)]+)\\))"  // Look for %(keys) to replace
    );

    private NamedFormatter() {}

    /**
     * Expands format strings containing <code>%(keys)</code>.
     *
     * <p>Examples:</p>
     *
     * <ul>
     * <li><code>NamedFormatter.format("Hello, %(name)!", Map.of("name", "200_success"))</code> → <code>"Hello, 200_success!"</code></li>
     * <li><code>NamedFormatter.format("Hello, \%(name)!", Map.of("name", "200_success"))</code> → <code>"Hello, %(name)!"</code></li>
     * <li><code>NamedFormatter.format("Hello, %(name)!", Map.of("foo", "bar"))</code> → <code>"Hello, %(name)!"</code></li>
     * </ul>
     *
     * @param fmt The format string.  Any character in the format string that
     *            follows a backslash is treated literally.  Any
     *            <code>%(key)</code> is replaced by its corresponding value
     *            in the <code>values</code> map.  If the key does not exist
     *            in the <code>values</code> map, then it is left unsubstituted.
     *
     * @param values Key-value pairs to be used in the substitutions.
     *
     * @return The formatted string.
     */
    public static String format(String fmt, Map<String, Object> values) {
        return RE.matcher(fmt).replaceAll(match ->
            match.group(1) != null ?
                match.group(1) :
                values.getOrDefault(match.group(3), match.group(2)).toString()
        );
    }
}
🌐
Codeline24
codeline24.com › home › java string templates
Java String Templates - Java and Spring Trends
September 5, 2024 - These placeholders are denoted by \{expression}. ... String name = "Alice"; int age = 30; String message = STR."\{name} is \{age} years old."; System.out.println(message); // Output: Alice is 30 years old.
🌐
Alvin Alexander
alvinalexander.com › blog › post › java › use-string-format-java-string-output
Java String formatting with the String.format method (like ‘sprintf’) | alvinalexander.com
July 30, 2024 - But, if you’re not familiar with this syntax, what happens in the line of code above is that the %d in my Java String is replaced by the value of the variable RENAME_SUCCEEDED, which in this case happens to be a constant in my class. The %d symbol is a placeholder that indicates that a decimal ...