[java] Sprintf equivalent in Java

Printf got added to Java with the 1.5 release but I can't seem to find how to send the output to a string rather than a file (which is what sprintf does in C). Does anyone know how to do this?

This question is related to java string formatting

The answer is


You can do a printf to anything that is an OutputStream with a PrintStream. Somehow like this, printing into a string stream:

PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s", "hello", 3, "friends");
System.out.println(baos.toString());
baos.reset(); //need reset to write new string
ps.printf("there is a %s from %d %s", "flip", 5, "haters");
System.out.println(baos.toString());
baos.reset();

The string stream can be created like this ByteArrayOutputStream:

ByteArrayOutputStream baos = new ByteArrayOutputStream();

Both solutions workto simulate printf, but in a different way. For instance, to convert a value to a hex string, you have the 2 following solutions:

  • with format(), closest to sprintf():

    final static String HexChars = "0123456789abcdef";
    
    public static String getHexQuad(long v) {
        String ret;
        if(v > 0xffff) ret = getHexQuad(v >> 16); else ret = "";
        ret += String.format("%c%c%c%c",
            HexChars.charAt((int) ((v >> 12) & 0x0f)),
            HexChars.charAt((int) ((v >>  8) & 0x0f)),
            HexChars.charAt((int) ((v >>  4) & 0x0f)),
            HexChars.charAt((int) ( v        & 0x0f)));
        return ret;
    }
    
  • with replace(char oldchar , char newchar), somewhat faster but pretty limited:

        ...
        ret += "ABCD".
            replace('A', HexChars.charAt((int) ((v >> 12) & 0x0f))).
            replace('B', HexChars.charAt((int) ((v >>  8) & 0x0f))).
            replace('C', HexChars.charAt((int) ((v >>  4) & 0x0f))).
            replace('D', HexChars.charAt((int) ( v        & 0x0f)));
        ...
    
  • There is a third solution consisting of just adding the char to ret one by one (char are numbers that add to each other!) such as in:

    ...
    ret += HexChars.charAt((int) ((v >> 12) & 0x0f)));
    ret += HexChars.charAt((int) ((v >>  8) & 0x0f)));
    ...
    

...but that'd be really ugly.


Strings are immutable types. You cannot modify them, only return new string instances.

Because of that, formatting with an instance method makes little sense, as it would have to be called like:

String formatted = "%s: %s".format(key, value);

The original Java authors (and .NET authors) decided that a static method made more sense in this situation, as you are not modifying the target, but instead calling a format method and passing in an input string.

Here is an example of why format() would be dumb as an instance method. In .NET (and probably in Java), Replace() is an instance method.

You can do this:

 "I Like Wine".Replace("Wine","Beer");

However, nothing happens, because strings are immutable. Replace() tries to return a new string, but it is assigned to nothing.

This causes lots of common rookie mistakes like:

inputText.Replace(" ", "%20");

Again, nothing happens, instead you have to do:

inputText = inputText.Replace(" ","%20");

Now, if you understand that strings are immutable, that makes perfect sense. If you don't, then you are just confused. The proper place for Replace() would be where format() is, as a static method of String:

 inputText = String.Replace(inputText, " ", "%20");

Now there is no question as to what's going on.

The real question is, why did the authors of these frameworks decide that one should be an instance method, and the other static? In my opinion, both are more elegantly expressed as static methods.

Regardless of your opinion, the truth is that you are less prone to make a mistake using the static version, and the code is easier to understand (No Hidden Gotchas).

Of course there are some methods that are perfect as instance methods, take String.Length()

int length = "123".Length();

In this situation, it's obvious we are not trying to modify "123", we are just inspecting it, and returning its length. This is a perfect candidate for an instance method.

My simple rules for Instance Methods on Immutable Objects:

  • If you need to return a new instance of the same type, use a static method.
  • Otherwise, use an instance method.

Since Java 13 you have formatted 1 method on String, which was added along with text blocks as a preview feature 2. You can use it instead of String.format()

Assertions.assertEquals(
   "%s %d %.3f".formatted("foo", 123, 7.89),
   "foo 123 7.890"
);

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to string

How to split a string in two and store it in a field String method cannot be found in a main class method Kotlin - How to correctly concatenate a String Replacing a character from a certain index Remove quotes from String in Python Detect whether a Python string is a number or a letter How does String substring work in Swift How does String.Index work in Swift swift 3.0 Data to String? How to parse JSON string in Typescript

Examples related to formatting

How to add empty spaces into MD markdown readme on GitHub? VBA: Convert Text to Number How to change indentation in Visual Studio Code? How do you change the formatting options in Visual Studio Code? (Excel) Conditional Formatting based on Adjacent Cell Value 80-characters / right margin line in Sublime Text 3 Format certain floating dataframe columns into percentage in pandas Format JavaScript date as yyyy-mm-dd AngularJS format JSON string output converting multiple columns from character to numeric format in r