46

To concatenate String we often use StringBuilder instead of String + String, but also we can do the same with String.format which returns the formatted string by given locale, format and arguments.

Examples:

Concatenate the string with StringBuilder

String concatenateStringWithStringBuilder(String name, String lName, String nick) {
    final StringBuilder sb = new StringBuilder("Contact {");
    sb.append(", name='").append(name)
      .append(", lastName='").append(lName)
      .append(", nickName='").append(nick)
      .append('}');
    return sb.toString();
}

Concatenate the string with StringFormat:

String concatenateStringWithStringFormat(String name, String lName, String nick) {
    return String.format("Contact {name=%s, lastName=%s, nickName=%s}", name, lName, nick);
}

In performance, is String.Format as efficient as StringBuilder? Which one is better to concatenate strings and why?

UPDATE

I checked the similar question, but doesn´t answer my question. So far I have used StringBuilder to concatenate strings, should I follow it using? Or should I use String.format? the question is which one is better and why?

gb96
  • 1,674
  • 1
  • 18
  • 26
JUAN CALVOPINA M
  • 3,695
  • 2
  • 21
  • 37
  • A quick benchmark won't take too much time – WoooHaaaa May 22 '17 at 16:26
  • 1
    A third option: `return "Contact {name=" + name + ", lastName=" + lName + ", nickName=" + nick + '}';` This would create the same bytecode as using StringBuilder and is just as readable as using String.Format. – Klitos Kyriacou May 22 '17 at 16:29
  • see this [Should I use Java's String.format() if performance is important?](https://stackoverflow.com/questions/513600/should-i-use-javas-string-format-if-performance-is-important) – Binu May 22 '17 at 16:32
  • 3
    Unless your method is being called thousands of times per second, you will not notice a difference in performance. You should not use StringBuilder or StringBuffer, simply because they are so much less readable. I would use String.format, because it makes very clear what your final string is intended to look like. – VGR May 22 '17 at 18:39

3 Answers3

38

What is "better" solely depends on your requirements:

  • For instance String Builder will be faster, but the code will be much more unreadable, and and it would be easier to make a mistake.

  • On the other hand String.format() produces more readable code at the cost of performance.

JMH benchmark to illustrate the performance difference (notice that the string builder code is longer and very hard to understand how the resulting string would look like):

@Fork(1)
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Measurement(iterations = 10)
@Warmup(iterations = 10)
@BenchmarkMode(Mode.Throughput)
public class StringFormatBenchmark {
    private String name = "UserName";
    private String lName = "LUserName";
    private String nick = "UserNick";

    @Benchmark
    public void stringFormat(Blackhole blackhole) {
        final String result = String.format("Contact {name=%s, lastName=%s, nickName=%s}", name, lName, nick);
        blackhole.consume(result);
    }

    @Benchmark
    public void stringBuilder(Blackhole blackhole) {
        final StringBuffer sb = new StringBuffer("Contact {");
        sb.append(", name='").append(name)
                .append(", lastName='").append(lName)
                .append(", nickName='").append(nick)
                .append('}');
        final String result = sb.toString();
        blackhole.consume(result);
    }
}

And the results:

Benchmark                             Mode  Cnt      Score     Error   Units
StringFormatBenchmark.stringBuilder  thrpt   10  10617.210 ± 157.302  ops/ms
StringFormatBenchmark.stringFormat   thrpt   10    960.658 ±   7.398  ops/ms

For non performance critical code I prefer using the String.format(), because it's easier and more pleasant to use. Also it's visible what the resulting string would look like, by simply looking at the pattern. If I'm doing a performance critical code, or something that has to have a low GC impact, I would use a StringBuilder because it's faster and can be reused.

Svetlin Zarev
  • 14,713
  • 4
  • 53
  • 82
  • how did you run it may I ask? – Faraz Aug 16 '18 at 11:37
  • @FarazDurrani Just run the "Launcher" with the test class name as parameter: https://github.com/SvetlinZarev/com.github.svetlinzarev.jmh.benchmarks/blob/master/src/main/java/com/github/svetlinzarev/jmh/benchmarks/Launcher.java – Svetlin Zarev Aug 16 '18 at 12:18
  • Thanks @Svetlin. I was able to run other JMH from google. But thanks though. – Faraz Aug 16 '18 at 13:05
  • 1
    I actually see StringBuilder as more readable and less prone to mistakes. I'm not used to the symbols of String.format(). And String.format() I need to pay more attention to the order of the itens, while in StringBuilder it's 1 per line, it's more organized. – The Student Jul 09 '21 at 16:09
20

After doing a little test with StringBuilder vs String.format I understood how much time it takes each of them to solve the concatenation. Here the snippet code and the results

Code:

String name = "stackover";
String lName = " flow";
String nick = " stackoverflow";
String email = "stackoverflow@email.com";
int phone = 123123123;

//for (int i = 0; i < 10; i++) {
long initialTime1 = System.currentTimeMillis();
String response = String.format(" - Contact {name=%s, lastName=%s, nickName=%s, email=%s, phone=%d}",
                                name, lName, nick, email, phone);
long finalTime1 = System.currentTimeMillis();
long totalTime1 = finalTime1 - initialTime1;
System.out.println(totalTime1 + response);

long initialTime2 = System.currentTimeMillis();
final StringBuilder sb = new StringBuilder(" - Contact {");
sb.append("name=").append(name)
  .append(", lastName=").append(lName)
  .append(", nickName=").append(nick)
  .append(", email=").append(email)
  .append(", phone=").append(phone)
  .append('}');
String response2 = sb.toString();
long finalTime2 = System.currentTimeMillis();
long totalTime2 = finalTime2 - initialTime2;
System.out.println(totalTime2 + response2);
//}

After of run the code several times, I saw that String.format takes more time:

String.format: 46: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 38: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 51: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}

But if I run the same code inside a loop, the result change.

String.format: 43: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 1: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 1: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}

The first time String.format runs it takes more time, after of that the time is shorter even though it does not become constant as a result of StringBuilder

As @G.Fiedler said: "String.format has to parse the format string..."

With these results it can be said that StringBuilder is more efficient thanString.format

JUAN CALVOPINA M
  • 3,695
  • 2
  • 21
  • 37
  • You could also test `String,concat` on either long and short strings – Ferrybig May 23 '17 at 06:29
  • 2
    Interesting idea to test the loop. It seems like the parsed format string is cached and reused instead of being parsed again on each loop iteration. Also, it makes since that StringBuilder is slower on subsequent loop iterations, because you are instantiating an entirely new StringBuilder on each iteration (assuming you literally just wrapped the same code with a loop). – Kingand Feb 19 '18 at 03:52
13

StringBuilder is faster, because String.format has to parse the format string (a complex domain specific language). And that's expensive.

StringBuilder instead of String + String

BTW: It's the same, because it results in the same byte code (since Java 1.5).

G. Fiedler
  • 664
  • 4
  • 12