Suponha que haja uma string, faremos muitas operações de emenda de loop nessa string, usando "+" obteremos o desempenho mais baixo. Mas quão ruim é esse desempenho? Qual seria o resultado se também colocássemos StringBuffer, StringBuilder ou String.concat() no teste de desempenho? Este artigo dará uma resposta a essas perguntas!
Usaremos Per4j para calcular o desempenho, pois esta ferramenta pode nos fornecer um conjunto completo de indicadores de desempenho, como o tempo mínimo e máximo gasto, o desvio padrão do período estatístico, etc. No código de teste, para obter um valor preciso do desvio padrão, realizaremos um teste de 20 emendas "*" 50.000 vezes. Aqui está o método que usaremos para concatenar strings:
Copie o código do código da seguinte forma:
Operador de concatenação (+)
Método concat de string concat (String str)
Método de acréscimo StringBuffer anexar (String str)
Método de acréscimo StringBuilder anexar (String str)
Finalmente, veremos o bytecode para ver exatamente como esses métodos são executados. Agora, vamos começar criando nossa classe. Observe que para calcular o desempenho de cada loop, cada código de teste no código precisa ser agrupado com a biblioteca Per4J. Primeiro definimos o número de iterações
Copie o código do código da seguinte forma:
final estático privado int OUTER_ITERATION=20;
final estático privado int INNER_ITERATION=50000;
A seguir, usaremos os 4 métodos acima para implementar nosso código de teste.
Copie o código do código da seguinte forma:
String addTestStr = "";
String concatTestStr = "";
StringBuffer concatTestSb = null;
StringBuilder concatTestSbu = null;
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringAddConcat");
addTestStr = "";
para (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
addTestStr += "*";
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringConcat");
concatTestStr = "";
para (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestStr.concat("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBufferConcat");
concatTestSb = new StringBuffer();
para (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSb.append("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBuilderConcat");
concatTestSbu = new StringBuilder();
para (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSbu.append("*");
stopWatch.stop();
}
Em seguida, execute o programa para gerar métricas de desempenho. Meu ambiente operacional é um sistema operacional Windows 7 de 64 bits, uma máquina JVM (7-ea) de 32 bits com 4 GB de memória e uma CPU dual-core Quad 2.00GHz.
Ficou perfeito como imaginamos. A única coisa interessante é por que String.concat também é muito bom. Todos nós sabemos que String é uma classe constante (uma classe que não muda após a inicialização), então por que o desempenho de concat é melhor? (Nota do tradutor: Na verdade, há um problema com o código de teste do autor original. O código de teste para o método concat() deve ser escrito como concatTestStr=concatTestStr.concat(“*”).) Para responder a isso pergunta, devemos olhar para a descompilação concat O bytecode aparece. O pacote de download deste artigo contém todos os bytecodes, mas agora vamos dar uma olhada neste trecho de código do concat:
Copie o código do código da seguinte forma:
46: novo #6; //class java/lang/StringBuilder
49: dup
50: invocaespecial #7; //Método java/lang/StringBuilder."<init>":()V
53: aload_1
54: invocarvirtual #8; //Método java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: ldc #9; //String *
59: invocarvirtual #8; //Método java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
62: invocarvirtual #10; //Método java/lang/StringBuilder.toString:()
Java/lang/String;
65: uma loja_1
66: iinc 7, 1
69: vá para 38
Este código é o bytecode de String.concat(). A partir deste código, podemos ver claramente que o método concat() usa StringBuilder. O desempenho de concat() deve ser tão bom quanto StringBuilder, mas devido à criação adicional de StringBuilder e. fazer a operação .append(str).append(str).toString() afetará o desempenho do concate, então StringBuilder e String Os tempos de cancate são 1,8 e 3,3.
Portanto, mesmo fazendo a concatenação mais simples, se não quisermos criar uma instância de StringBuffer ou StringBuilder, devemos usar concat. Mas para um grande número de operações de emenda de string, não devemos usar concat (Nota do tradutor: como o código de teste não é completamente equivalente em função, o tempo médio de processamento de concat no código de teste substituído é de 1.650,9 milissegundos. Este resultado está no comentário de texto original. ), porque concat reduzirá o desempenho do seu programa e consumirá sua CPU. Portanto, para obter o mais alto desempenho sem considerar a segurança e a sincronização do thread, devemos tentar usar o StringBuilder.