Guia Linguagem Java

Diferenças entre String, StringBuilder e StringBuffer em Java

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (20)  (0)

Veja neste artigo as principais diferenças entre String, StringBuilder e StringBuffer em Java e veja como otimizar a sua aplicação usando-as corretamente.

Já vimos muitos desenvolvedores usar StringBuilder ou StringBuffer sem nem ao menos saber qual o real impacto de sua utilização em detrimento da String “normal”. Neste artigo explicaremos com detalhes e exemplos a diferença entre String, StringBuilder e StringBuffer. Assim você será capaz de julgar com eficácia qual melhor recurso para fazer uso em um momento adequado.

Muitos preferem o uso de concatenação de strings usando o operador “+”, porém você verá neste arquivo o quão problemático pode ser o uso deste operador com frequência em toda a aplicação, e provavelmente a partir deste artigo você dará mais importância ao uso do StringBuilder e StringBuffer, quando necessário.

Strings são imutáveis

Você já deve ter lido ou ouvido em algum lugar algo sobre: “String são imutáveis”, ou seja, você não pode mudar seu valor após a primeira atribuição. Então você se pergunta: se Strings são imutáveis, então porque eu consigo concatenar vários valores a uma String, tornando-a diferente da original?

Acontece que na verdade você não está “concatenando” nada, e sim criando um novo objeto em memória. Cada vez que você acha que está concatenando uma String com outra, você está criando diversos objetos distintos em memória, e as Strings “antigas” perdem referência, mas continuam lá. Vamos ver um exemplo na Listagem 1 para entender o que acontece por trás dos panos.

Listagem 1. Entendendo a “falsa” concatenação com a classe String

  public class ConcatenaString {
         
         public static void main (String[] args){
               
               //Cria um objeto em memória
               String str = "hello";
               
               /*
                * Sabemos que nossa string agora será: "hello world".
                *
                * Ocorre que é criada a String "world" em memória,
                 * depois a JVM cria um outro objeto "hello world".
                * No total vão ser 3 objetos para que essa 'concatenação'
                * ocorra.
                * */
               str.concat(" world");
               
               
               /*
                * O mesmo conceito é aplicado acima. É criada uma string 
                 * "from java" em memória, depois é criada uma
                * nova juntando "hello world from java".
                * No total temos agora 5 objetos em memória,
                * sendo que apenas 1 estamos utilizando, 
                * veja que desperdício.
                * */
               str += " from Java";
               
         }
   
  }

Caso você não esteja convencido que usar concatenação dessa forma é muito prejudicial a performance da aplicação, vamos ver o teste da Listagem 2.

Listagem 2. Concatenando 65536 caracteres (caractere por caractere)

   public class ConcatenaString {
         
         public static void main (String[] args){
               
               
               String strFinal = "";
               
               /*
                * Vamos concatenar 65536 vezes o caractere 'a',
                * então entenda que cada vez que passarmos no laço
                * a JVM irá criar um novo objeto em memória.
                * */
               for(int i = 0; i < 65536; i ++){
                      strFinal += "a";                  
               }
         }
   
  }

Veja quanto tempo demora em executar o código acima na sua máquina.

StringBuilder vs String

Como você já deve ter percebido, a String não deve ser usada para concatenação de outras Strings ou caracteres. Na seção acima apenas falamos sobre o quão prejudicial pode ser o seu uso, mas agora vamos comparar tal uso com o StringBuilder, que é a maneira correta de concatenar Strings ou caracteres.

Vamos usar o mesmo exemplo da Listagem 2 com algumas modificações para vermos de fato a velocidade de execução do StringBuilder e do String em concatenar valores, agora sim ficará nítido a diferença entre estes. Observe a Listagem 3.

Listagem 3. Comparando performance de String e StringBuilder

  public class ConcatenaString {
         
         public static void main (String[] args){
               
                      
               
               /*
                * ###########################################
                * INICIO BLOCO CONCATENAÇÃO COM OPERADOR '+'
                * ###########################################
                * */
               String strFinal = "";
               long tStart = System.currentTimeMillis();
               /*
                * Vamos concatenar 65536 vezes o caractere 'a',
                * então entenda que cada vez que passarmos no laço
                * a JVM irá criar um novo objeto em memória.
                * */
               for(int i = 0; i < 100000; i ++){
                      strFinal += "a";                  
               }
               
               long tEnd = System.currentTimeMillis();
               long tResult = tEnd - tStart;
               
               System.out.println("Tempo de Execução com operador 
                '+' = "+tResult+" ms");
               
               /*
                * ###########################################
                * FIM BLOCO CONCATENAÇÃO COM OPERADOR '+'
                * ###########################################
                * */
               
               
               
               /*
                * ###########################################
                * INICIO BLOCO CONCATENAÇÃO COM StringBuilder
                * ###########################################
                * */
               StringBuilder strBuilder = new StringBuilder();
               tStart = System.currentTimeMillis();
               for(int i = 0; i < 100000; i ++){
                      strBuilder.append("a");                 
               }
               tEnd = System.currentTimeMillis();
               tResult = tEnd - tStart;
               System.out.println("Tempo de Execução com StringBuilder 
                 = "+tResult+" ms");
         }
   
  }
  Saída provável:
  Tempo de Execução com operador '+' = 3753 ms
  Tempo de Execução com StringBuilder = 4 ms

Na máquina em que executamos o código acima, a saída foi 3753ms para o String com operador '+' e 4ms para o StringBuilder. Usamos apenas 100mil caracteres, mas imagine se fossem 1 milhão de caracteres? Faça você mesmo esse teste.

Perceba que para não tornar o testo tendencioso, colocar o tStart (tempo inicial) e o tEnd (tempo final) bem no início e no fim do laço for, desconsiderando qualquer outro código que venha antes ou depois, como atribuições e escritas no console, assim avaliamos puramente a concatenação de ambos.

Sem dúvida a performance do StringBuilder em detrimento do String comum é exponencialmente melhor quando precisamos concatenar valores. Isso foi provado com a Listagem 3. Acontece que o StringBuilder é mutável, ou seja, a cada “append(valor)” que fizemos no laço concatenamos de fato um novo valor a String já existente, sem a necessidade da criação de um novo objeto em memória.

Quando usar o operador '+'

Bom, se falamos que o operador '+' não deve ser usado para concatenação de Strings, pois cria novos objetos em memória, então em que situação deve-se usá-lo? Há uma situação ou ele nunca deve ser usado?

Sim, há situações em que ele deve ser usado, que são aquelas em que você irá juntar uma enorme String para facilitar a legibilidade do código, sem a necessidade de criação de um novo objeto, ou mais conhecido por “multi-line Strings”. Veja o exemplo da Listagem 4.

Listagem 4. Usando o operador '+' em momentos oportunos

  public class ConcatenaString {
         
         public static void main (String[] args){
               
               /*
                * A nossa string abaixo é um uso ideal para o operador '+', 
                * pois não estamos criando nenhum novo objeto em memória, 
                * apenas melhorando a
                * legibilidade do código.
                * */
               String strFinal = "Feliz " +
                                            "Natal " +
                                            "Aos Leitores "+
                                            "da DEVMEDIA "+
                                            "hohoho...";
               
               //Também poderiamos usar desta forma sem 
               //prejudicar a performance do programa
               int x = 10;
               int y = 20;
               System.out.println("x:"+x+" y:"+y);
         }
   
  }

StringBuilder vs StringBuffer

Ambos são bem mais rápidos para concatenação de valores do que a String comum e fazem exatamente a mesma função. A principal diferença é que o StringBuffer é sincronizado, enquanto que o outro não. Assim, você garante a consistência do seu código quando há diversas threads lendo ou modificando a mesma String. Para esses casos, o ideal é usar o StringBuffer.

Porém o StringBuilder ainda é mais rápido do que o StringBuffer: veja o teste feito através da Listagem 5.

Listagem 5. Comparação performance StringBuilder e StringBuffer

  public class ConcatenaString {
         
         public static void main (String[] args){
               long tStart, tEnd, tResult;
               
               /*
                * ###########################################
                * INICIO BLOCO CONCATENAÇÃO COM StringBuilder
                * ###########################################
                * */
               StringBuilder strBuilder = new StringBuilder();
               tStart = System.currentTimeMillis();
               for(int i = 0; i < 100000; i ++){
                      strBuilder.append("a");                 
               }
               tEnd = System.currentTimeMillis();
               tResult = tEnd - tStart;
               System.out.println("Tempo de Execução com StringBuilder = 
                "+tResult+" ms");
               /*
                * ###########################################
                 * FIM BLOCO CONCATENAÇÃO COM StringBuilder
                * ###########################################
                * */
               
               /*
                * ###########################################
                * INICIO BLOCO CONCATENAÇÃO COM StringBuffer
                * ###########################################
                * */
               StringBuffer strBuffer = new StringBuffer();
               tStart = System.currentTimeMillis();
               for(int i = 0; i < 100000; i ++){
                      strBuffer.append("a");                  
               }
               tEnd = System.currentTimeMillis();
               tResult = tEnd - tStart;
               System.out.println("Tempo de Execução com StringBuffer =
                "+tResult+" ms");
               /*
                * ###########################################
                * FIM BLOCO CONCATENAÇÃO COM StringBuffer
                * ###########################################
                * */
         }
   
  }
   
  Saída Provável:
  Tempo de Execução com StringBuilder = 7 ms
  Tempo de Execução com StringBuffer = 11 ms

Veja também o gráfico da Figura 1 ilustrando outro exemplo: perceba que a diferença é mínima, tendo alguns picos em momentos específicos da execução.

Comparação de Performance

Figura 1. Comparação de Performance

Finalizamos esse artigo com um conceito bem ilustrado e exemplificado sobre as diferenças entre String, StringBuilder e StringBuffer.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?