1. Imutabilidade de String: amiga ou inimiga?
Em Java, a classe String é imutável (immutable). Isso significa que, depois de criada, a string não pode ser alterada. Toda vez que você “altera” uma string, por exemplo, adicionando algo com + ou concat(), na verdade é criado um novo objeto, e o antigo vai para a lixeira da história (e da memória).
Exemplo:
String s = "Hello";
s = s + " world!";
System.out.println(s); // Hello world!
Parece que a string s mudou, mas na realidade foi criada uma nova string "Hello world!", e a antiga "Hello" permanece na memória até que o coletor de lixo a remova. Se tais operações forem muitas — por exemplo, em um loop — o programa começa a ficar lento e a usar memória desnecessária.
Imagine que você está construindo uma torre de blocos e, sempre que quer adicionar um novo bloco, precisa reconstruir a torre inteira do zero. Nada econômico, certo? É assim que o String comum funciona em Java quando há alterações frequentes.
2. StringBuilder: o “construtor” de strings rápido
A classe StringBuilder (pacote java.lang, não é necessário importar) é uma ferramenta especial para montar e modificar strings de forma eficiente. Ela é mutável (mutable): você pode adicionar, remover e inserir caracteres e substrings sem criar um novo objeto para cada operação.
Analogias:
Se String é uma laje de concreto, então StringBuilder é um conjunto LEGO: você adiciona e remove peças à vontade sem desmontar tudo.
Como criar um StringBuilder
StringBuilder sb = new StringBuilder(); // vazio
StringBuilder sb2 = new StringBuilder("Valor inicial");
Principais métodos
| Método | Descrição | Exemplo de uso |
|---|---|---|
|
Adicionar ao final uma string, número, caractere etc. | |
|
Inserir o valor na posição especificada | |
|
Remover caracteres da posição start (incl.) até end (excl.) | |
|
Substituir parte da string por outro conteúdo | |
|
Inverter a string | |
|
Converter para uma string normal | |
|
Cortar ou completar a string até o comprimento especificado | |
Exemplo de uso
StringBuilder sb = new StringBuilder();
sb.append("Olá, ");
sb.append("mundo!");
System.out.println(sb); // Olá, mundo!
sb.insert(7, "Java "); // vamos inserir "Java " depois de "Olá, "
System.out.println(sb); // Olá, Java mundo!
sb.replace(8, 12, "outro"); // vamos substituir "Java" por "outro"
System.out.println(sb); // Olá, outro mundo!
sb.reverse();
System.out.println(sb); // !odnum ortuo ,álO
3. StringBuffer: irmão mais velho com segurança para múltiplas threads
Qual é a diferença entre StringBuilder e StringBuffer?
- StringBuilder — rápido, mas não é thread-safe (não sincronizado).
- StringBuffer — mais lento, porém thread-safe (sincronizado).
Se seu aplicativo funciona em uma única thread, use StringBuilder (mais rápido). Se várias threads puderem modificar a mesma string, use StringBuffer.
4. Quando usar StringBuilder em vez de String?
Cenários
- Alterações frequentes na string (adição, remoção, inserção) em loops ou ao montar textos grandes.
- Montagem de uma string a partir de um array/lista (CSV, HTML, relatórios etc.).
- Parsing e processamento de texto com muitas operações sobre a string.
Exemplo: montagem de string a partir de um array
Maneira ruim (com String e +):
String[] names = {"Ivan", "Pyotr", "Maria"};
String result = "";
for (int i = 0; i < names.length; i++)
{
result += names[i];
if (i < names.length - 1)
{
result += ", ";
}
}
System.out.println(result);
Maneira boa (com StringBuilder):
String[] names = {"Ivan", "Pyotr", "Maria"};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < names.length; i++)
{
sb.append(names[i]);
if (i < names.length - 1)
{
sb.append(", ");
}
}
System.out.println(sb.toString());
Diferença: no primeiro caso, a cada passo é criada uma nova string; no segundo, nós vamos acumulando em um único objeto StringBuilder.
5. Comparação de desempenho: String vs StringBuilder
// Usando String
long t1 = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 10000; i++)
{
s += i + " ";
}
long t2 = System.currentTimeMillis();
System.out.println("String: " + (t2 - t1) + " ms");
// Usando StringBuilder
t1 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.append(i).append(" ");
}
s = sb.toString();
t2 = System.currentTimeMillis();
System.out.println("StringBuilder: " + (t2 - t1) + " ms");
Conclusão: na maioria dos casos, StringBuilder é ordens de grandeza mais rápido em concatenações múltiplas.
6. Dicas úteis
Posso usar os métodos de String?
StringBuilder tem seus próprios métodos. Para obter uma string, chame toString().
StringBuilder sb = new StringBuilder("Hello");
String s = sb.toString(); // agora s é uma string comum
Posso comparar StringBuilder com equals?
Cuidado: sb1.equals(sb2) compara referências, não o conteúdo. Compare assim:
if (sb1.toString().equals(sb2.toString()))
{
// o conteúdo é igual
}
Posso passar StringBuilder para System.out.println?
Sim. System.out.println chamará toString() automaticamente.
Posso ler caracteres por índice?
Sim, use charAt(int index), como em uma string comum.
7. Erros típicos ao trabalhar com StringBuilder e StringBuffer
Erro nº 1: comparar dois StringBuilder com equals ou o operador ==. Essas verificações comparam referências, não o conteúdo. Use toString() e compare as strings.
Erro nº 2: esquecer de chamar toString() onde é esperado um String (retorno de método, logging, passagem para APIs).
Erro nº 3: usar StringBuilder para um par de concatenações simples. A forma "Hello, " + name é legível e eficiente.
Erro nº 4: concatenar String em um loop usando +. Isso é ineficiente em tempo e memória — use StringBuilder.
Erro nº 5: confundir StringBuffer com StringBuilder sem necessidade. Se não houver modificação simultânea por múltiplas threads, prefira StringBuilder.
Erro nº 6: truncar o conteúdo de StringBuilder com setLength() sem pensar. Verifique a correção do novo tamanho; os dados após ele serão perdidos.
GO TO FULL VERSION