StringBuilder e StringBuffer em Java

StringBuilder e StringBuffer em Java

1. Visão geral

Neste breve artigo, veremos as semelhanças e diferenças entreStringBuilder eStringBuffer em Java.

Simplificando,StringBuilder foi introduzido no Java 1.5 como um substituto paraStringBuffer.

2. Semelhanças

TantoStringBuildereStringBuffer criam objetos que contêma mutable sequence of characters. Vamos ver como isso funciona e como se compara a uma classeString imutável:

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

Mesmo que pareça que estamos modificando o mesmo objeto anexando“def”, estamos criando um novo porque as instâncias deString não podem ser modificadas.

Ao usarStringBuffer ouStringBuilder,, podemos usar o métodoappend():

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

Nesse caso, não havia novo objeto criado. Chamamos o métodoappend() na instânciasbe modificamos seu conteúdo. StringBuffereStringBuilder são objetos mutáveis.

3. Diferenças

StringBuffer é sincronizado e, portanto, thread-safe. StringBuilder é compatível com a APIStringBuffer, mas sem garantia de sincronização.

Por não ser uma implementação thread-safe, é mais rápida e é recomendado usá-la em lugares onde não há necessidade de thread safety.

3.1. atuação

Em pequenas iterações, a diferença de desempenho é insignificante. Vamos fazer um micro-benchmark rápido comJMH:

@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;
}

Usamos o modoThroughput padrão - ou seja, operações por unidade de tempo (maior pontuação é melhor), o que fornece:

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

Se aumentarmos o número de iterações de 1k para 1m, obtemos:

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

No entanto, vamos ter em mente que este é um micro-benchmark, que pode ou não ter um impacto real no desempenho real de um aplicativo no mundo real.

4. Conclusões

Simplificando,StringBuffer é uma implementação thread-safe e, portanto, mais lenta do queStringBuilder.

Em programas single-threaded, podemos usarStringBuilder. Ainda assim,the performance gain of StringBuilder over StringBuffer may be too small to justify replacing it everywhere. É sempre uma boa ideia criar o perfil do aplicativo e entender suas características de desempenho de tempo de execução antes de fazer qualquer tipo de trabalho para substituir uma implementação por outra.

Finalmente, como sempre, o código usado durante a discussão pode ser encontradoover on GitHub.