StringBuilder vs StringBuffer in Java – Java中的StringBuilder vs StringBuffer

最后修改: 2017年 9月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this short article, we’re going to look at similarities and differences between StringBuilder and StringBuffer in Java.

在这篇短文中,我们将看看Java中的StringBuilderStringBuffer之间的相似之处和区别。

Simply put, StringBuilder was introduced in Java 1.5 as a replacement for StringBuffer.

简单地说, StringBuilder是在Java 1.5中引入的,作为StringBuffer的替代。

2. Similarities

2.相似之处

Both StringBuilder and StringBuffer create objects that hold a mutable sequence of characters. Let’s see how this works, and how it compares to an immutable String class:

StringBuilderStringBuffer都创建了持有可变的字符序列的对象。让我们看看这是如何工作的,以及它与不可变的String类相比的情况。

String immutable = "abc";
immutable = immutable + "def";

Even though it may look like that we’re modifying the same object by appending “def”, we are creating a new one because String instances can’t be modified.

尽管看起来我们通过添加“def”来修改同一个对象,但我们正在创建一个新的对象,因为String实例不能被修改。

When using either StringBuffer or StringBuilder, we can use the append() method:

当使用StringBufferStringBuilder,我们可以使用append()方法。

StringBuffer sb = new StringBuffer("abc");
sb.append("def");

In this case, there was no new object created. We have called the append() method on sb instance and modified its content. StringBuffer and StringBuilder are mutable objects.

在这种情况下,并没有创建新的对象。我们对sb实例调用了append()方法并修改了它的内容。StringBufferStringBuilder是可变的对象。

3. Differences

3.差异

StringBuffer is synchronized and therefore thread-safe. StringBuilder is compatible with StringBuffer API but with no guarantee of synchronization.

StringBuffer是同步的,因此是线程安全的。StringBuilderStringBuffer API兼容,但不能保证同步性。

Because it’s not a thread-safe implementation, it is faster and it is recommended to use it in places where there’s no need for thread safety.

因为它不是一个线程安全的实现,所以它更快,建议在不需要线程安全的地方使用它。

3.1. Performance

3.1.性能

In small iterations, the performance difference is insignificant. Let’s do a quick micro-benchmark with JMH:

在小规模的迭代中,性能差异是不明显的。让我们用JMH做一个快速的微型测试。

@State(Scope.Benchmark)
public static class MyState {
    int iterations = 1000;
    String initial = "abc";
    String suffix = "def";
}

@Benchmark
public StringBuffer benchmarkStringBuffer(MyState state) {
    StringBuffer stringBuffer = new StringBuffer(state.initial);
    for (int i = 0; i < state.iterations; i++) {
        stringBuffer.append(state.suffix);
    }
    return stringBuffer;
}

@Benchmark
public StringBuilder benchmarkStringBuilder(MyState state) {
    StringBuilder stringBuilder = new StringBuilder(state.initial);
    for (int i = 0; i < state.iterations; i++) {
        stringBuilder.append(state.suffix);
    }
    return stringBuilder;
}

We have used the default Throughput mode – i.e. operations per unit of time (higher score is better), which gives:

我们使用了默认的Throughput模式–即每单位时间内的操作(分数越高越好),这就得到了。

Benchmark                                          Mode  Cnt      Score      Error  Units
StringBufferStringBuilder.benchmarkStringBuffer   thrpt  200  86169.834 ±  972.477  ops/s
StringBufferStringBuilder.benchmarkStringBuilder  thrpt  200  91076.952 ± 2818.028  ops/s

If we increase the number of iterations from 1k to 1m then we get:

如果我们将迭代次数从1k增加到1m,那么我们会得到。

Benchmark                                          Mode  Cnt   Score   Error  Units
StringBufferStringBuilder.benchmarkStringBuffer   thrpt  200  77.178 ± 0.898  ops/s
StringBufferStringBuilder.benchmarkStringBuilder  thrpt  200  85.769 ± 1.966  ops/s

However, let’s bear in mind that this is a micro-benchmark, which may or may not have a real impact on the actual, real-world performance of an application.

然而,我们要记住,这是一个微观的基准测试,它可能对一个应用程序的实际、真实世界的性能产生或不产生真正的影响。

4. Conclusions

4.结论

Simply put, the StringBuffer is a thread-safe implementation and therefore slower than the StringBuilder.

简单地说,StringBuffer是一个线程安全的实现,因此比StringBuilder慢。

In single-threaded programs, we can take of the StringBuilder. Yet, the performance gain of StringBuilder over StringBuffer may be too small to justify replacing it everywhere. It’s always a good idea to profile the application and understand its runtime performance characteristics before doing any kind of work to replace one implementation with another.

在单线程程序中,我们可以使用StringBuilder。然而,StringBuffer相比,StringBuilder的性能增益可能太小,不足以证明在任何地方都可以取代它。在做任何一种工作以取代另一种实现之前,对应用程序进行剖析并了解其运行时性能特征总是一个好主意。

Finally, as always, the code used during the discussion can be found over on GitHub.

最后,像往常一样,讨论中使用的代码可以在GitHub上找到