Melhores práticas / desempenho: combinando StringBuilder.append com String.concat

86

Estou tentando entender qual é a prática recomendada e por que concatenar literais de string e variáveis ​​para casos diferentes. Por exemplo, se eu tiver um código como este

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

É assim que se faz? A partir dessa postagem , percebi que o +operador em Strings cria uma nova instância de StringBuilder, concatena os operandos e retorna uma conversão de String, o que parece muito mais trabalhoso do que apenas chamar .append(); então, se isso for verdade, está fora de questão. Mas e quanto String.concat()? É apropriado usar .append()para cada concatenação? Ou apenas para variáveis ​​e literais podem ser acrescentados .concat()?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

Quais são as regras gerais de melhores práticas e desempenho para lidar com essas situações? Minha suposição está correta +e realmente não deveria ser usada?

Nick Rolando
fonte
Acho que basicamente você entendeu. As opiniões divergem sobre se String + "realmente não deve ser usado". O ponto é que você entende as consequências
ControlAltDel

Respostas:

184

+ operador

String s = s1 + s2

Nos bastidores, isso se traduz em:

String s = new StringBuilder(s1).append(s2).toString();

Imagine quanto trabalho extra isso adiciona se você tiver s1 + s2aqui:

stringBuilder.append(s1 + s2)

ao invés de:

stringBuilder.append(s1).append(s2)

Várias strings com +

Vale a pena notar que:

String s = s1 + s2 + s3 + ... +sN

é traduzido para:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

Stringcria uma char[]matriz que pode caber em s1e s2. Cópias s1e s2conteúdos para esta nova matriz. Na verdade, requer menos trabalho do que o +operador.

StringBuilder.append()

Mantém uma char[]matriz interna que cresce quando necessário. Nenhum extra char[]é criado se o interno for suficientemente grande.

stringBuilder.append(s1.concat(s2))

também é um mau desempenho, porque s1.concat(s2)cria um extra char[]array e cópias s1e s2para ele só para copiar esse novo conteúdo da matriz para interna StringBuilder char[].

Dito isso, você deve usar append()o tempo todo e anexar strings brutas (seu primeiro trecho de código está correto).

Tomasz Nurkiewicz
fonte
Obrigado pela sua ajuda e pela explicação detalhada; era disso que eu realmente precisava.
Nick Rolando,
12
Embora as versões mais recentes do compilador otimizem automaticamente o operador + para um construtor de strings, não é necessariamente bom presumir que o fará, pois as versões anteriores não o fazem. Há um tópico muito importante que está sendo ignorado em toda essa discussão que é, na verdade, um dos principais objetivos do StringBuilder, que é o pool de strings. Usar um construtor de string mantém tudo como um char [] e não cria uma String intermediária como o operador + fazia antes das otimizações do compilador (usado apenas para fazer um concat). Usar concat cria um objeto String intermediário que é armazenado em cache, mas não usado.
LINEMAN78
Portanto, se estou fazendo uma declaração única (não várias declarações em um método), concatenação em várias strings diferentes. Seria correto usar +nos objetos String em vez de criar uma StringBuilderconcatenação única, já que basicamente fará a mesma coisa?
Nick Rolando,
1
E se eu quiser concatenar apenas um caractere, é melhor usar .append ('\ n') em vez de .append ("\ n")? Como um personagem é um tipo primitivo e uma String é um Objeto?
vrwim
3
Java 2ª edição efetiva : Usar o operador de concatenação de string repetidamente para concatenar n strings requer tempo quadrático em n. Então, ainda é relevante?
gkiko
16

O compilador otimiza a concatenação +.

então

int a = 1;
String s = "Hello " + a;

é transformado em

new StringBuilder().append("Hello ").append(1).toString();

Há um excelente tópico aqui explicando porque você deve usar o operador +.

Andy Turner
fonte
3
O compilador iria realmente otimizar isso, String s = "Hello World";pois você usa literais.
ColinD
@ColinD: +1. Acabei de modificar meu trecho.
3

A otimização é feita automaticamente pelo compilador.

O compilador Java2 converterá automaticamente o seguinte:

String s = s1 + s2; 

para

String s = (new StringBuffer()).append(s1).append(s2).toString();

Retirado diretamente do site Java Best Practices on Oracles.

Valentes como o amor
fonte
2

Você deve sempre usar append.

concatcrie uma nova String para que seja bem como +eu penso.

Se você concatou usar +com 2 String finais, a JVM pode fazer a otimização, então é o mesmo que fazer append neste caso.

alain.janinm
fonte
1

Se você concatou exatamente duas Strings, use String.concat (cria uma nova String criando uma nova matriz de caracteres que se ajusta a ambas as Strings e copia as matrizes de caracteres de ambas as Strings nela).

Se você concatou várias (mais de duas) Strings em uma linha, use + ou StringBuilder.append, não importa, pois o compilador converte + em StringBuilder.append. Isso é bom para várias Strings porque mantém uma matriz char que cresce conforme necessário.

Se você concatou várias Strings em várias linhas, crie um StringBuilder e use o método append. No final, quando terminar de anexar Strings ao StringBuilder, use seu método .toString () para criar uma String a partir dele. Para concateamento em várias linhas, isso é mais rápido do que o segundo método, já que o segundo método criaria um novo StringBuilder em cada linha, acrescentaria as Strings e então lançaria de volta para String, enquanto o terceiro método só usa um StringBuilder para a coisa toda.

Dakkaron
fonte
0

Usar +operador é a melhor prática, também é simples e legível.

A linguagem Java fornece suporte especial para o operador de concatenação de string (+) e para a conversão de outros objetos em strings. A concatenação de string é implementada por meio da classe StringBuilder (ou StringBuffer) e seu método append.

Documento oficial: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

Do Nhu Vy
fonte
0

no nível de código de byte não é diferente e não estamos comprometendo a eficácia aí. No caso de execução de nível de código de byte, ele deve passar pelo método de sobrecarga de operador não embutido para + chamando append. em seguida, no nível de linguagem assembly (Java é escrito em C e C produz assemblies semelhantes ao assembly, haverá uma chamada de registro extra para store + chamada de método na pilha e haverá um push adicional. (na realidade, cross-compiler pode otimizar + operador chamada, nesse caso, não fazendo diferença com a eficiência.)

É uma boa prática ter uma maneira de aumentar a legibilidade. :)

Shevon Silva
fonte
0

Eu pessoalmente prefiro o formatador de strings deStrings.format() uma linha simples e fácil de ler .

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F
T04435
fonte
0

Todas as respostas são muito boas e explicativas. Mas eu senti que explorar outras técnicas de concatenação de strings também ajudaria, como - Guava Joiner, Streams, String.format etc.

Para obter detalhes completos sobre o desempenho de cada técnica de concatenação java-string-concatenation-which-way-is-best .

Em resumo, o desempenho da concatenação varia sem. de strings para concatenar. Por exemplo - para concatenar de 1 a 10 strings, essas técnicas funcionam melhor - StringBuilder, StringBuffer e Plus Operator. E para concatenar centenas de strings - Guava Joiner, a biblioteca stringsUtils do apache também funciona muito bem.

Por favor, vá até o blog acima. Isso realmente explica muito bem a eficiência do desempenho.

Obrigado.

coderAJ
fonte