Recentemente fiz um curso de Spring, e como curiosidade o professor Douglas Campos, citou uma coisa muitíssimo interessante: hoje usar o operador + para concatenar string pode ser uma boa opção em grande parte dos casos (a partir da hotspot do Java 6). Porque o compilador vai transformar isto para a concatenação com StringBuilder.
Isto me deixou muito intrigado, e foi procurar alguma referência oficial da Sun para escrever este post, e disseminar esta informação. Encontrei, cumprindo a premissa de quem procura acha!!! Porém!!! Achei a referencia de performance da Sun um pouco antiga, e lá no capitulo sobre imutabilidade ele diz o seguinte:
String result = "";
for (int i=0; i < 20; i++) {
result += getNextString();
}
Concatenating String objects
The javac compiler would automatically transform this to
String result = "";
for (int i=0; i < 20; i++) {
result = new StringBuffer().append(result)
.append(getNextString())
.toString();
}
Observe que é StringBuffer, mas como o StringBuffer não é mais recomendado pela Oracle/Sun (Sei lá como chamo isto), isto foi atualizado para usar o StringBuilder.
Se alguém tiver uma referência oficial atualizada sobre isto post por favor!
Está correto! A unica questao é que a partir do Java 5 o compilador vai gerar com StringBuilder e não com StringBuffer.
Realmente é preciso pensar com cuidado nas otimizacoes que fazemos com concatenacoes de strings porque no fundo é tudo StringBuilder. Mas esse caso de concatenar num for é um classico onde ainda precisamos escrever o StringBuilder na mao para nao sofrer com a performance.
Repare que quando voce faz o for com + o compilador gera a concatenacao com StringBuilder. Mas como voce atribui o resultado de volta numa String, ele precisa criar um StringBuilder novo a cada iteracao e chamar o toString de volta. O que, claro, não é muito performatico se voce precisar da String so no final do for (repare que o compilador nao tem como saber isso, por isso gera o codigo “ruim”).
Para melhorar a performance, vc precisa fazer o codigo classico de criar o StringBuilder fora do for e depois só chamar o append dentro do laço. E após o for chamar o toString uma unica vez. Aí vai ficar bem mais rapido!
E um ultimo comentario: o compilador transforma concatenacoes de String em StringBuffer/Builder desde sempre (não só Java 6). O que mudou foi que no Java 5 em diante ele deixou de usar StringBuffer e passou a usar StringBuilder.
Apenas acrescentando, tem um post do paulo silveira (pt-br) e um paper bem interessante a respeito de performance de concatenação de strings (inglês). Vale a leitura!
Agora, note que num loop, o uso do StringBuilder implícito pela VM não criou nada mais otimizado. O loop que você mesmo colocou mostra isso: É criado um stringBuffer a cada iteração, e sobre ele é chamado o toString(), resultando numa nova String. O custo de alocação desse novo objeto ainda existe e, portanto, não houve ganho de performance.
O que seu professor falou, é que para os casos das concatenações simples, isso já está otimizado:
[code]String nome = “Vinicius”;
String sobrenome = “Godoy de Mendonça”;
public void String getSobrenome() {
return nome + " " + sobrenome;
}[/code]
É equivalente a:
public void String getSobrenome() {
return new StringBuilder(nome).append(" ").append(sobrenome).toString();
}
Agora, num loop, você ainda precisa criar o StringBuilder manualmente.
Eu realmente havia feito alguns testes com isto, para o caso de concatenação simples sempre utilizei StringBuffer e depois StringBuilder por que não tinha este conhecimento que o compilador fazia este esforço para otimizar (claro que depois desta explicação de vocês podemos definir como proibitivo para os casos que vai concatenar em um looping), me parece que esta otimização é uma coisa pouco conhecida pela comunidade Java. Muito obrigado pelas referências, os testes e a paciência!