String.format和StringBuilder之间的性能

JUA*_*A M 15 java stringbuilder string.format

为了连接,String我们经常使用StringBuilder而不是String+ String,但我们也可以String.format通过给定的语言环境,格式和参数来返回格式化的字符串.

例子:

使用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();
}
Run Code Online (Sandbox Code Playgroud)

使用StringFormat连接字符串:

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

在性能方面,String.Format效率如何StringBuilder?哪一个更好地连接字符串,为什么?

UPDATE

我检查了类似的问题,但没有回答我的问题.到目前为止,我已经习惯StringBuilder连接字符串,我应该使用它吗?或者我应该使用String.format?问题是哪个更好,为什么?

Sve*_*rev 18

什么是"更好"完全取决于您的要求:

  • 例如String Builder会更快,但代码将更加难以理解,并且更容易犯错误.

  • 另一方面String.format(),以性能为代价产生更易读的代码.

JMH基准测试用于说明性能差异(注意字符串构建器代码更长,很难理解结果字符串的外观):

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

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
Run Code Online (Sandbox Code Playgroud)

对于非性能关键代码,我更喜欢使用String.format(),因为它更容易使用.通过简单地查看模式,可以看到结果字符串的外观.如果我正在执行性能关键代码,或者必须具有低GC影响的代码,我会使用a,StringBuilder因为它更快并且可以重用.

  • 实际上,我认为 StringBuilder 更具可读性并且更不容易出错。我不习惯 String.format() 的符号。而 String.format() 我需要更多地注意 itens 的顺序,而在 StringBuilder 中它是每行 1 个,它更有组织性。 (3认同)

G. *_*ler 9

StringBuilder更快,因为String.format必须解析格式字符串(一种复杂的域特定语言).那很贵.

StringBuilder而不是String + String

BTW:它是一样的,因为它产生相同的字节代码(从Java 1.5开始).


JUA*_*A M 6

StringBuilder对vs 做一点测试之后,String.format我了解了每个人解决串联所需的时间。这是代码段和结果

码:

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);
//}
Run Code Online (Sandbox Code Playgroud)

多次运行代码后,我看到这String.format花费了更多时间:

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}
Run Code Online (Sandbox Code Playgroud)

但是,如果我在循环中运行相同的代码,结果将发生变化。

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}
Run Code Online (Sandbox Code Playgroud)

第一次String.format运行会花费更多时间,此后时间会变短,即使由于StringBuilder

正如@ G.Fiedler所说:“ String.format必须解析格式字符串...”

有了这些结果,可以说StringBuilderString.format

  • 测试循环的有趣想法。似乎已解析的格式字符串已缓存并重新使用,而不是在每次循环迭代时再次被解析。同样,由于在后续循环迭代中StringBuilder的速度较慢,这也使它成为可能,因为您在每次迭代中实例化了一个全新的StringBuilder(假设您实际上只是用循环包装了相同的代码)。 (2认同)