views:

992

answers:

12

I wonder why Java 5 and above provide a printf-style formatter using a static method in class String like this:

public static String format(String format, Object... args)

instead of

public String format(Object... args)

so that we can write "%02d".format(5) to get 05 instead of String.format("%02d", 5).

I imagined if I could modify the String class, I could add this:

public String format(Object... args) {
    return format(this, args)
}

to get the same result.

I found that in C#, a static method is also used instead of an instance method.

I wonder why they decided to do this, but I didn't come to an explanation. The instance methods trim and substring returns a new instance of string, so they should have done the same thing with format.

Moreover, the DateFormat class also uses this:

public final String format(Date date)

for formatting dates. So if we consider the instance of DateFormat as the formatter, an instance of String could also be used as a formatter.

Any ideas?

+2  A: 

The main reason is probably that the designers of Java did not want to add too much stuff to the interface of String. Making it a member function would have meant putting it on string. Remember that a non-static method would have to be on the String object.

A second reason is that the static format maintains its resemblance to C's printf, which looks like printf(FORMAT, ARG1, ARG2...)

Another reason is that format is overloaded: there is a version that takes locale as the first parameter (before the string), so doing this on the string object would be tricky.

Uri
A: 

Possibly to show that it's a "utility" function that exists for convenience, but which isn't really an intrinsic function of a String. That is, the String "%02d" is a way of representing a format, but it doesn't actually do any formatting.

The method exists for convenient formatting of Strings, but Formatter (which performs the actual formatting) can also format other types of objects (Date, etc).

harto
+5  A: 

Perhaps "%02d".format(5) seems to imply that the object on which the format method is being called is a format string.

In this case, the format string happens to also be a String, so furthering that point, one could argue that all Strings are format strings.

Probably this can be avoided by saying that a static method in the String class can be used to format a string, rather than making some implicit statement about all Strings in general.

coobird
That seems like a reasonable point
Andy White
True, thanks for this! This reminds me of public boolean matches(String regex) which has a similar pattern to this.
yuku
+4  A: 

"%02d".format(5) would look like "%02d" is formatted using the format 5 rather than the opposite. Also most strings are not suitable as format ("hello world".format(5)?), so the method should throw exceptions for most string objects.

ggf31416
A: 

In C#, strings are immutable. I think that's true in Java too (not 100% sure about that). So, you are not changing the string by calling a format method on it, you are only returning a new string with the formatting. That makes it a class-level method and not an instance-level method, thus it is static. You can add an instance level facade in C# using an extension function, but that is simply syntactic sugar on top of a static function.

JP Alioto
You're right, the same applies to Java string too.
arul
-1 because this can be said of every function in the string class, not just about Format.
Samuel
Don't blame me. Most methods on a String (in c# at least) do not imply any mutation. The ones that do imply mutation all return a string. But, with format it is very clear that there is no reason to force you to make the string first.
JP Alioto
You're making a String either way. This does nothing to answer the question. It doesn't matter a great deal. For some other methods, like length(), it makes clear sense (from a OO) perspective, to "ask" the String. Does it make sense to ask the String to format some objects? ggf31416 notes correctly most Strings /can't/ format anything. So, maybe not.
Matthew Flaschen
You're making a String either way. This does nothing to answer the question. I don't think it matters much, personally. For some other methods, like length(), it makes clear sense (from a OO perspective), to "ask" the String. Does it make sense to ask the String to format some objects? ggf31416 notes correctly most Strings /can't/ format anything. So, maybe not.
Matthew Flaschen
+3  A: 

Answer rests in responsibility of Format method.

It is more logical and intuitive, at least to me, to say that "format string is input to Format method" than to say that "Format operates on format string". This is so, as we "usually" pass format string, known at design time, to Format. In contrast, for Trim, we "usually" pass variable string whose value is not known at design time.

So, making format method static, make code reading more intuitive. Look at following (C#).

answer = String.Format("This is format string : {0}", someValue); 
//More readable to me

answer = "This is format string : {0}".Format(someValue);

EDIT: Even though I have used C# example code, it applies well to Java. I got -ve vote for using C# syntax!

isntn
This is a Java question though. It would probably help to use the Java syntax over the C# example.
dlamblin
Hi, dlamblinThough it is tagged as Java question, it as well applies to C# as noted by questioner. I think, it is unfair to reduce reputation as my answer (please ready text part before looking at my example code) applies to Java, too! I request you to remove negative vote.
isntn
Thanks, dlamblin.
isntn
A: 

Merely because the call is reminiscent of C's sprintf function.

dlamblin
A: 

Probably because String is immutable and therefore this method has to create and return a new instance of String instance. If the method was not declared static, you would probably expect it to modify the String instance on which it has been called.

Shai
A: 

I think it is not mandatory that Java make any construct similar to anything else, even C++. Anything adopted must be so because the developers accept it. Besides, arguments like "they made it similar to something else" do not explain why they don't just make an instance method version, they do this with primitive wrappers (in addition to the instance toString() method, they have the static version).

This is what I think:

On a normal case, both forms are equivalent, but suppose that we have something like:

String invalidFormat = "%invalid"; // or something else that is invalid

and then we call:

String.format(invalidFormat, anything);
// "anything" is indeed anything....

the invalid become the argument and Java clarify this by throwing an instance of IllegalArgumentException (even in the case of Formatter, there are many kinds).

However, in something like:

invalidFormat.format(anything);

the invalid one is no longer the argument. The problem now lies with the instance it is called on and so is probaby better described as an "invalid state" (not Java's "IllegalStateException", which has a completely different usage). But because Strings are immutable, this so called "state" will never change, so it will always remain invalid as a format, even though it is a valid simple string.

Compare this with, say, java.lang.Long. Both versions of toString will never throw any exception, so they are both equivalent.

RichN
+1  A: 

While I am not a designer of Java, I can tell you one clear reason for making it static.

Java 5 came out with many features, but two of note were:

  • The ability to perform "import static" commands that allowed static methods to be used from within a class easily and without listing their class name.
  • A static utility method that performed printfs easily.

While it'd be nice to be able to say "bla: %d".format("foo"), by making the method static you can use format in a way that's very familiar and clean-looking to C programmers used to printf().

import static java.lang.String.format;

public class Demo {

   public void Test() {

      //Do some stuff

      format("Hey, this is easy to read!");

   }
 }

And that's why! By using static imports, printfs look almost exactly like they do in C. Awesome!

CaptainAwesomePants
Nice! I didn't think of that. Although I think what you want to say is java.lang.String.format not java.lang.String.printf ;)
yuku
Yeah, I was kind of tired when I wrote that. Fixed it :)
CaptainAwesomePants
A: 

Calling strfmt.format(objects) instead of String.format(strfmt, objects)

  • is an Object Orientated call instead of a call to a static helper.
  • its shorter to type.
  • its simpler as it has one less argument.
  • its easier to use with code completion. If you start with the format string and hit . you get the format() as an option in an IDE.
  • String.format(strfmt, objects) could be accidental called as strfmt.format(text, objects) which wouldn't do what it appears to do.
Peter Lawrey
How does this answer the question?
Michael Myers
A: 

I really think `format' must be an instance method of String and so also do
- python:
2.6: print "%s" % ("Hello")
3.0: print("{0}".format("Hello"))
- scala:
2.7.6: println("%s".format("Hello"))

Vitja
And in Java: System.out.printf("%s%n", "Hello"); I use printf() most of the time rather than String.format().
Peter Lawrey