16

I'm writing a MUD (text based game) at the moment using java. One of the major aspects of a MUD is formatting strings and sending it back to the user. How would this best be accomplished?

Say I wanted to send the following string:

You say to Someone "Hello!" - where "Someone", "say" and "Hello!" are all variables. Which would be best performance wise?

"You " + verb + " to " + user + " \"" + text + "\""

or

String.format("You %1$s to %2$s \"%3$s\"", verb, user, text)

or some other option?

I'm not sure which is going to be easier to use in the end (which is important because it'll be everywhere), but I'm thinking about it at this point because concatenating with +'s is getting a bit confusing with some of the bigger lines. I feel that using StringBuilder in this case will simply make it even less readable.

Any suggestion here?

Textmode
  • 509
  • 3
  • 18
two13
  • 345
  • 1
  • 3
  • 11
  • 9
    Don't worry about performance unless you find it's an issue and that this is the bottleneck. Do whatever you think will lead to the most readable and maintainable code. – Luigi Plinge Oct 15 '11 at 06:09

8 Answers8

30

If the strings are built using a single concatenation expression; e.g.

String s = "You " + verb + " to " + user + " \"" + text + "\"";

then this is more or less equivalent to the more long winded:

StringBuilder sb = new StringBuilder();
sb.append("You");
sb.append(verb);
sb.append(" to ");
sb.append(user);
sb.append(" \"");
sb.append(text );
sb.append('"');
String s = sb.toString();

In fact, a classic Java compiler will compile the former into the latter ... almost. In Java 9, they implemented JEP 280 which replaces the sequence of constructor and method calls in the bytecodes with a single invokedynamic bytecode. The runtime system then optimizes this1.

The efficiency issues arise when you start creating intermediate strings, or building strings using += and so on. In some cases, using an explicit StringBuilder can be2 more efficient because you are reduce the amount of copying.

Now when you use String.format(), it should be using a StringBuilder under the hood. However, format also has to parse the format String each time you make the call, and that is an overhead you don't have if you do the string building optimally.


Having said this, My Advice would be to write the code in the way that is most readable. Only worry about the most efficient way to build strings if profiling tells you that this is a real performance concern. (Right now, you are spending time thinking about ways to address a performance issue that may turn out to be insignificant or irrelevant.)

Another answer mentions that using a format string may simplify support for multiple languages. This is true, though there are limits as to what you can do with respect to such things as plurals, genders, and so on.


1 - As a consequence, hand optimization as per the example above might actually have negative consequences, for Java 9 or later. But this is a risk you take whenever you micro-optimize.
2 - Analyzing and predicting when this happens in general is difficult.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • 1
    Thanks for the detailed explanation, it helped me think things through. I'm going to go with String.format as it's a) a built in solution and b) already making my life easier by making the strings much more readable. – two13 Oct 16 '11 at 02:29
2

I think that concatenation with + is more readable than using String.format.

String.format is good when you need to format number and dates.

CoffeeRain
  • 4,460
  • 4
  • 31
  • 50
user997135
  • 39
  • 3
  • Seems to be the most neat & convinent choice, and it's implemented via `java.util.Formatter`. – Eric Jul 03 '19 at 06:29
1

Concateneting with plus, the compilet can transforms the code in performatic way. With string format i don t know.

I prefer cocatenation with plus, i think that is easer to undersand.

Tarcísio Júnior
  • 1,239
  • 7
  • 15
1

The key to keeping it simple is to never look at it. Here is what I mean:

Joiner join = Joiner.on(" ");

public void constructMessage(StringBuilder sb, Iterable<String> words) {
  join.appendTo(sb, words);
}

I'm using the Guava Joiner class to make readability a non-issue. What could be clearer than "join"? All the nasty bits regarding concatenation are nicely hidden away. By using Iterable, I can use this method with all sorts of data structures, Lists being the most obvious.

Here is an example of a call using a Guava ImmutableList (which is more efficient than a regular list, since any methods that modify the list just throw exceptions, and correctly represents the fact that constructMessage() cannot change the list of words, just consume it):

StringBuilder outputMessage = new StringBuilder();
constructMessage(outputMessage, 
         new ImmutableList.Builder<String>()
            .add("You", verb, "to", user, "\"", text, "\"")
            .build());
Steve J
  • 2,676
  • 20
  • 18
0

I think String.format looks cleaner. However you can use StringBuilder and use append function to create the string you want

Saurabh
  • 7,894
  • 2
  • 23
  • 31
0

I will be honest and suggest that you take the first one if you want less typing, or the latter one if you are looking for a more C-style way of doing it.

I sat here for a minute or two pondering the idea of what could be a problem, but I think it comes down to how much you want to type.

Anyone else have an idea?

nmagerko
  • 6,586
  • 12
  • 46
  • 71
  • My reasoning behind it is more about readability. I'm pretty used to typing " stuff " + " other stuff" and will probably have to break myself from that habit if I go with another option. What I was originally thinking was something like "You [verb] to [user] [text]" and do a replaceall (class driven, so I'd add the variables like setElement("verb", verb) and then it would spit back a formatted string), but stumbled across .format and figured my original idea would be terrible with performance (but super easy to read). – two13 Oct 15 '11 at 02:59
0

Assuming you are going to reuse base strings often Store your templates like

String mystring = "You $1 to $2 \"$3\""

Then just get a copy and do a replace $X with what you want.

This would work really well for a resource file too.

Jake Thompson
  • 301
  • 1
  • 3
-3

The best, performance-wise, would probably be to use a StringBuffer.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • 3
    Disagree. From the [`StringBuilder`](http://download.oracle.com/javase/1.5.0/docs/api/java/lang/StringBuilder.html) javadoc: Where possible, it is recommended that this class be used in preference to `StringBuffer` as it will be faster under most implementations. --- Btw., I doubt that string concatenation is the bottleneck in such an application. – michael667 Oct 15 '11 at 04:52
  • 1
    Same difference, one synchronized, one not. When synchronization is properly implemented the difference is negligible if there's no contention. (And, obviously, one would not want to use StringBuilder if there is contention.) – Hot Licks Oct 15 '11 at 12:03