Concatenação de Strings em Laços
Jonas Abreu em 11/04/2012No post sobre String, StringBuffer e StringBuilder, comentei que em geral não faz diferença você usar qualquer um deles.
Conheço um caso em que isso pode não ser verdade.
Vejam o seguinte código inocente:
String a = "";
for (int i = 0; i < 100000; i++) {
a += "a";
}
E comparem com a versão que usa StringBuider:
StringBuilder a = new StringBuilder("");
for (int i = 0; i < 100000; i++) {
a.append("a");
}
Na minha máquina, q primeira demora 28595ms
para rodar, enquanto que a segunda roda em 27ms
. Uma diferença
de mais de 1000 vezes.
Olhando o bytecode do primeiro exemplo, entendemos o problema.
0: ldc #25; //String
2: astore_1
3: iconst_0
4: istore_2
5: goto 31
8: new #27; //class java/lang/StringBuilder
11: dup
12: aload_1
13: invokestatic #29; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
16: invokespecial #35; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
19: ldc #38; //String a
21: invokevirtual #40; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/
StringBuilder;
24: invokevirtual #44; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: astore_1
28: iinc 2, 1
31: iload_2
32: ldc #48; //int 100000
34: if_icmplt 8
37: return
As linhas interessantes são as identificadas por 16, 21 e 24, que compõe parte da concatenação de strings dentro do laço.
A 16 é a invocação do construtor de um StringBuilder
. Depois é chamado o método append
e enfim é chamado o
toString
.
Mas não existia nenhuma referência à StringBuilder
no primeiro exemplo. Ele aparece aí porque o compilador Java,
quando encontra uma concatenação de strings, converte para um StringBuilder automaticamente.
Na maioria das vezes isso funciona bem. O problema é que nesse caso a otimização do compilador não ajudou.
Isso significa que você não vai mais concatenar strings dentro de laço sem usar StringBuilder
? Não. Caso
apareça no seu profiler esse problema, daí sim vale a pena trocar para um StringBuilder
.