300

Primitive question, but how do I format strings like this:

"Step {1} of {2}"

by substituting variables using Java? In C# it's easy.

2

12 Answers 12

319

Take a look at String.format. Note, however, that it takes format specifiers similar to those of C's printf family of functions -- for example:

String.format("Hello %s, %d", "world", 42);

Would return "Hello world, 42". You may find this helpful when learning about the format specifiers. Andy Thomas-Cramer was kind enough to leave this link in a comment below, which appears to point to the official spec. The most commonly used ones are:

  • %s - insert a string
  • %d - insert a signed integer (decimal)
  • %f - insert a real number, standard notation

This is radically different from C#, which uses positional references with an optional format specifier. That means that you can't do things like:

String.format("The {0} is repeated again: {0}", "word");

... without actually repeating the parameter passed to printf/format. (see The Scrum Meister's comment below)


If you just want to print the result directly, you may find System.out.printf (PrintStream.printf) to your liking.

3
  • 2
    Another option is java.text.MessageFormat, which does accept the {1} style format symbols. String.format()'s format symbols can be similar to C's printf() format symbols -- but can also differ. See download.oracle.com/javase/6/docs/api/java/util/… for the full syntax. Commented Jun 21, 2011 at 21:11
  • 71
    String.format can also take numeric positions: String.format("%2$s %1$s", "foo", "bar"); will output bar foo Commented Jun 21, 2011 at 21:18
  • 11
    Starting from Java 15 it is possible to use String.format directly on the String using String.formatted(). "Hello %s, %d".formatted("world", 42)
    – twobiers
    Commented Dec 21, 2021 at 9:57
180

In addition to String.format, also take a look java.text.MessageFormat. The format less terse and a bit closer to the C# example you've provided and you can use it for parsing as well.

For example:

int someNumber = 42;
String someString = "foobar";
Object[] args = {new Long(someNumber), someString};
MessageFormat fmt = new MessageFormat("String is \"{1}\", number is {0}.");
System.out.println(fmt.format(args));

A nicer example takes advantage of the varargs and autoboxing improvements in Java 1.5 and turns the above into a one-liner:

MessageFormat.format("String is \"{1}\", number is {0}.", 42, "foobar");

MessageFormat is a little bit nicer for doing i18nized plurals with the choice modifier. To specify a message that correctly uses the singular form when a variable is 1 and plural otherwise, you can do something like this:

String formatString = "there were {0} {0,choice,0#objects|1#object|1<objects}";
MessageFormat fmt = new MessageFormat(formatString);
fmt.format(new Object[] { new Long(numberOfObjects) });
6
  • 31
    MessageFormat is for localization purposes, so take care when using it. For example the following code MessageFormat.format("Number {0}", 1234)); depending on default locale can produce Number 1,234 instead of Number 1234. Commented Dec 4, 2012 at 10:25
  • @ataylor : Hello, Sorry but I am little confused. I want to something like that I ll pass Class object that has data & when {0} it ll take firstname, when {1} then lastname, like so. Is it possible like {0,choice,0.getFirstName()} or something like that ? Commented Dec 8, 2014 at 7:07
  • @user3145373ツ I don't think so.
    – ataylor
    Commented Dec 8, 2014 at 15:25
  • Ok fine, I have refer one .Net project like that I want, codeproject.com/Articles/42310/…, refer this project I am looking like this. If you know any project or packages available like that then please tell me. Thank you Commented Dec 10, 2014 at 9:54
  • 1
    ❗️ MessageFormat is orders of magnitude slower than String.format — avoid it unless you plan to live forever. This should NOT be the accepted answer.
    – ccpizza
    Commented Feb 11, 2022 at 17:44
60

New JDK features

String templates since Java 21 (as the first preview)

Introduced as JEP-460 (Preview) in Java 21 and later as JEP-459 (Second Preview) in Java 22. The API is not definitive and this part of the answer is a subject of changes.

This enhancement brings template processors for performing string interpolation.

  • STR is statically imported implicitly and interpolated immediatelly:
    int x = 10;
    int y = 20;
    // results in "10 + 20 = 30"
    String result = STR."\{x} + \{y} = \{x + y}";
    
  • RAW must be statically imported explicitly and the interpolation is deffered:
    int x = 10;
    int y = 20;
    StringTemplate st = RAW."\{x} + \{y} = \{x + y}";
    ...
    // results in "10 + 20 = 30"
    String result = STR.process(st);
    
  • FMT combines STR with Java's Formatter:
    int x = 10;
    int y = 20;
    // results in "10 + 20 =      30.00"
    String result = FMT."%d\{x} + %d\{y} = %7.2f\{x + y}";
    

Format-first since Java 15, alternative to String#format

There is a new instance method called String#formatted(Object... args) as of Java 15.

The internal implementation is the same as String#format(String format, Object... args).

Formats using this string as the format string, and the supplied arguments.

String step1 = "one";
String step2 = "two";

// results in "Step one of two"
String string = "Step %s of %s".formatted(step1, step2);     

Advantage: The difference is that the method is not static and the formatting pattern is a string itself from which a new one is created based on the args. This allows chaining to build the format itself first.

Disadvantage: There is no overloaded method with Locale, therefore uses the default one. If you need to use a custom Locale, you have to stick with String#format(Locale l, String format, Object... args).


Old JDK features

These are not deprecated and remain relevant until today.

String#format

The most frequent way to format a String is using this static method, that is long available since Java 5 and has two overloaded methods:

The method is easy to use and the format pattern is defined by underlying formatter.

String step1 = "one";
String step2 = "two";

// results in "Step one of two"
String string = String.format("Step %s of %s", step1, step2); 

You can pass a Locale to respect the language and regional specification. Refer to this answer for more information: https://stackoverflow.com/a/6431949/3764965 (credits to Martin Törnwall).

MessageFormat

The MessageFormat class is available since the first version of Java and is suitable for internationalization. In the simplest form, there is a static method for formatting:

String step1 = "one";
String step2 = "two";

// results in "Step one of two"
String string = MessageFormat.format("Step {0} of {1}", step1, step2);

Remember MessageFormat follows a specific pattern different from String#format, refer to its JavaDoc for more details: MessageFormat - patterns.

It is possible to use Locale, however, one has to instantiate the object of the class and pass it to the constructor since the static method above uses the default constructor with the default locale. Refer to this answer for more information: https://stackoverflow.com/a/6432100/3764965 (credits to ataylor).

StringBuilder and String concatenation

These are well known and described anywhere else.


Non-JDK solutions

There are plenty of ways to format Strings using external libraries. They add little to no benefit if the libraries are imported solely for the purpose of String formatting. Few examples:

  • Apache Commons: StringSubstitutor, examples in its JavaDoc.
  • Cactoos: FormattedText, examples here.
  • Interestingly, Guava doesn't plan to add formatting or templating features: #1142.
  • ... and other custom implementations.

Feel free to add more, however, I find no reason to further expand this section.

3
  • 2
    Nice! Too bad I'm still working with Java 8 right now. We're debating to move either to Java 11 or Java 14 in the next year or so... so we probably won't be able to use this feature for another 3-5 years. Commented Sep 22, 2020 at 20:50
  • I'd be more optimistic. The LTS version will be Java 17 as of September 2021 so this feature might get handy. I haven't noticed such structural changes like the modular system between the 8 and 9 versions so I believe the migration will be faster :))
    – Nikolas
    Commented Sep 22, 2020 at 21:10
  • The preview feature "String Templates" was removed from Java 23: bugs.openjdk.org/browse/JDK-8329949
    – Vladislav
    Commented Dec 6 at 10:50
14

If you choose not to use String.format, the other option is the + binary operator

String str = "Step " + a + " of " + b;

This is the equivalent of

new StringBuilder("Step ").append(String.valueOf(1)).append(" of ").append(String.valueOf(2));

Whichever you use is your choice. StringBuilder is faster, but the speed difference is marginal. I prefer to use the + operator (which does a StringBuilder.append(String.valueOf(X))) and find it easier to read.

2
  • 10
    If you're going to neg rep me, please explain why.
    – Ryan Amos
    Commented Nov 12, 2011 at 17:08
  • 12
    1) In response to a question on string formatting, you explain how the + operator works. 2) Your explanation isn't even accurate. + is equivalent to using StringBuilder, not String.concat. (Way too much info on this.) Commented Sep 4, 2012 at 8:01
9

I've wrote my simple method for it :

public class SomeCommons {
    /** Message Format like 'Some String {0} / {1}' with arguments */
    public static String msgFormat(String s, Object... args) {
        return new MessageFormat(s).format(args);
    }
}

so you can use it as:

SomeCommons.msgFormat("Step {1} of {2}", 1 , "two");
6
public class StringFormat {

    public static void main(String[] args) {
            Scanner sc=new Scanner(System.in);
            System.out.println("================================");
            for(int i=0;i<3;i++){
                String s1=sc.next();
                int x=sc.nextInt();
                System.out.println(String.format("%-15s%03d",s1,x));
            }
            System.out.println("================================");

    }
}

outpot "================================"
ved15space123 ved15space123 ved15space123 "================================

Java solution

  • The "-" is used to left indent

  • The "15" makes the String's minimum length it takes up be 15

  • The "s" (which is a few characters after %) will be substituted by our String
  • The 0 pads our integer with 0s on the left
  • The 3 makes our integer be a minimum length of 3
1
5

JEP 430: String Templates (Preview)

You can use Java's String Templates feature. It is described in JEP 430, and it appears in JDK 21 as a preview feature.

Here is an example use:

String name = "Joan";
String info = STR."My name is \{name}";
assert info.equals("My name is Joan");   // true

Java's string templates are more versatile, and much safer, than features in other languagues such as C#'s string interpolation and Python's f-strings. For example, string concatenation or interpolation makes SQL injection attacks possible:

String query = "SELECT * FROM Person p WHERE p.last_name = '" + name + "'";
ResultSet rs = conn.createStatement().executeQuery(query);

but this variant (from JEP 430) prevents SQL injection:

PreparedStatement ps = DB."SELECT * FROM Person p WHERE p.last_name = \{name}";
ResultSet rs = ps.executeQuery();
2
  • Sad, why it's so long to have this... God Please... :') Java 17 doesn't have this then.. Commented Nov 1, 2023 at 9:15
  • 1
    @BenyaminLimanto No version of Java has this yet. Only in preview in Java 21. To understand preview, see JEP 12: Preview Features. Commented Nov 20, 2023 at 0:10
3

Apache Commons Text's StringSubstitutor provides a simple and readable way to format Strings with named variables.

import org.apache.commons.text.StringSubstitutor;
// ...
Map<String, String> values = new HashMap<>();
values.put("animal", "quick brown fox");
values.put("target", "lazy dog");
StringSubstitutor sub = new StringSubstitutor(values);
String result = sub.replace("The ${animal} jumped over the ${target}.");
// "The quick brown fox jumped over the lazy dog."

This class supports providing default values for variables.

String result = sub.replace("The number is ${undefined.property:-42}.");
// "The number is 42."

To use recursive variable replacement, call setEnableSubstitutionInVariables(true);.

Map<String, String> values = new HashMap<>();
values.put("b", "c");
values.put("ac", "Test");
StringSubstitutor sub = new StringSubstitutor(values);
sub.setEnableSubstitutionInVariables(true);
String result = sub.replace("${a${b}}");
// "Test"
2

This solution worked for me. I needed to create urls for a REST client dynamically so I created this method, so you just have to pass the restURL like this

/customer/{0}/user/{1}/order

and add as many params as you need:

public String createURL (String restURL, Object ... params) {       
    return new MessageFormat(restURL).format(params);
}

You just have to call this method like this:

createURL("/customer/{0}/user/{1}/order", 123, 321);

The output

"/customer/123/user/321/order"

2

java.util.Formatter

Java has the java.util.Formatter which is used internally for String formatting methods. It's quite powerful, albeit more complex to use.

Here is a guide for what you should use depending on your version of Java.

Java 15 and later

Call instance method String#formatted.

// Sequential string arguments
"foo %s baz %s".formatted("bar", "foobar");

// Indexed string arguments
"foo %1$s baz %2$s".formatted("bar", "foobar");

Java 5 to Java 14

Call static method String.format.

// Sequential string arguments
String.format("foo %s baz %s", "bar", "foobar");

// Indexed string arguments
String.format("foo %1$s baz %2$s", "bar", "foobar");

Java 4 and earlier

MessageFormat.format("foo {0} baz {1}", "bar", "foo");

That last example is for completeness' sake, and you should not be using it since it's the slowest of all options.

1
  • 1
    I still find the earliest solution (the latest mentioned) as the best one in terms of flexibility as you can mention a placeholder multiple times without repeating the argument. Also, it is easy to follow the attributes as they are numbered. On the other hand, the Java 15 approach does not support Locale and is not meant as a full substitution to String#format.
    – Nikolas
    Commented Jan 3 at 8:39
1

I wrote this function it does just the right thing. Interpolate a word starting with $ with the value of the variable of the same name.

private static String interpol1(String x){
    Field[] ffield =  Main.class.getDeclaredFields();
    String[] test = x.split(" ") ;
    for (String v : test ) {
        for ( Field n: ffield ) {
            if(v.startsWith("$") && ( n.getName().equals(v.substring(1))  )){
                try {
                    x = x.replace("$" + v.substring(1), String.valueOf( n.get(null)));
                }catch (Exception e){
                    System.out.println("");
                }
            }
        }
    }
    return x;
}
0

The org.apache.commons.text.StringSubstitutor helper class from Apache Commons Text provides named variable substitution

Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String resolved = new StringSubstitutor(valuesMap).replace("The ${animal} jumped over the ${target}.");
System.out.println(resolved); // The quick brown fox jumped over the lazy dog.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.