Pergunta de Entrevista em Java: Diferenças entre StringBuffer e StringBuilder, Analisadas a Partir do Código Fonte

Comparação Técnica entre StringBuffer e StringBuilder

As classes StringBuffer e StringBuilder compartilham uma hierarquia de herança comum, ambas estendendo a classe abstrata AbstractStringBuilder. Essa estrutura permite que compartilhem implementações básicas de operações de manipulação de strings mutáveis.

Mecanismo de Expansão de Capacidade

A capacidade de armazenamento é gerenciada por meio de um array de caracteres (char[]) não final, permitindo realocações dinâmicas. Quando o espaço disponível é insuficiente, ocorre a expansão automática através do método ensureCapacity:

public void ensureCapacity(int capacidadeMinima) { if (capacidadeMinima > 0) garantirCapacidadeInterna(capacidadeMinima); }

private void garantirCapacidadeInterna(int capacidadeMinima) { if (capacidadeMinima - value.length > 0) { value = Arrays.copyOf(value, calcularNovaCapacidade(capacidadeMinima)); } }

private int calcularNovaCapacidade(int capacidadeMinima) { int novaCapacidade = (value.length << 1) + 2; if (novaCapacidade - capacidadeMinima < 0) { novaCapacidade = capacidadeMinima; } return (novaCapacidade <= 0 || MAX_ARRAY_SIZE - novaCapacidade < 0) ? resolverCapacidadeExcessiva(capacidadeMinima) : novaCapacidade; }

private int resolverCapacidadeExcessiva(int capacidadeMinima) { if (Integer.MAX_VALUE - capacidadeMinima < 0) { throw new OutOfMemoryError(); } return (capacidadeMinima > MAX_ARRAY_SIZE) ? capacidadeMinima : MAX_ARRAY_SIZE; }


</div>O cálculo padrão dobra a capacidade atual e aidciona 2 posições. Em casos de overflow ou necessidade de grandes alocações, são aplicadas estratégias de contingência.

#### Segurança em Ambiente Concorrente

Para demonstrar as diferenças de thread safety, analisamos os métodos críticos:

- `StringBuffer`: Métodos sincronizados com modificador `synchronized`<div>```
    
    @Override
    public synchronized StringBuffer append(long valor) {
        toStringCache = null;
        super.append(valor);
        return this;
    }
    
    ```
    
    </div>
- `StringBuilder`: Implementação não sincronizada <div>```
    
    @Override
    public StringBuilder append(double valor) {
        super.append(valor);
        return this;
    }
    
    ```
    
    </div>

#### Teste de Concorrência

Um teste com 1000 threads simultâneas demonstra as diferenças práticas:

<div>```

import java.util.concurrent.CountDownLatch;

public class TesteConcorrencia {
    public static void main(String[] args) throws InterruptedException {
        StringBuffer bufferThreadSafe = new StringBuffer();
        StringBuilder builderNaoThreadSafe = new StringBuilder();
        
        CountDownLatch latch1 = new CountDownLatch(1000);
        CountDownLatch latch2 = new CountDownLatch(1000);

        // Teste com StringBuilder
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> {
                try {
                    builderNaoThreadSafe.append('a');
                } finally {
                    latch1.countDown();
                }
            }).start();
        }

        // Teste com StringBuffer
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> {
                try {
                    bufferThreadSafe.append('a');
                } finally {
                    latch2.countDown();
                }
            }).start();
        }

        latch1.await();
        System.out.println("Tamanho StringBuilder: " + builderNaoThreadSafe.length());
        latch2.await();
        System.out.println("Tamanho StringBuffer: " + bufferThreadSafe.length());
    }
}

  • StringBuffer sempre retorna 1000 caracteres (comportamento consistente)
  • StringBuilder frequentemente retorna valores menores que 1000 (colisões de acesso concorrente)

Conclusão Técnica

  • Ambas compartilham implementação abstrata para operações básicas
  • O mecanismo de expansão é implementado na classe pai AbstractStringBuilder
  • StringBuffer prioriza segurança com sincronização, enquanto StringBuilder otimiza desempenho em contextos single-thread
  • A escolha entre elas deve considerar requisitos de concorrência e performence

Tags: java StringBuffer StringBuilder Concorrência análise de código-fonte

Publicado em 9-11 14:20