Dadas as 2 toString()
implementações abaixo, qual é a preferida:
public String toString(){
return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}
ou
public String toString(){
StringBuilder sb = new StringBuilder(100);
return sb.append("{a:").append(a)
.append(", b:").append(b)
.append(", c:").append(c)
.append("}")
.toString();
}
?
Mais importante, como temos apenas três propriedades, isso pode não fazer a diferença, mas em que momento você mudaria de +
concat para StringBuilder
?
java
performance
string
concatenation
stringbuilder
não sequestrador
fonte
fonte
StringBuilder
quanto tamanho será alocado antecipadamente, caso contrário, se ficar sem espaço, terá que dobrar o tamanho criando um Uma novachar[]
matriz copia os dados - o que é caro. Você pode trapacear, fornecendo o tamanho e, em seguida, não há necessidade dessa criação de matriz - portanto, se você acha que sua string terá aproximadamente 100 caracteres, poderá definir o StringBuilder para esse tamanho e nunca precisará ser expandido internamente.Respostas:
A versão 1 é preferível porque é mais curta e o compilador a transformará na versão 2 - nenhuma diferença de desempenho.
No ponto em que você está concatenando em um loop - geralmente é quando o compilador não pode substituir
StringBuilder
por si mesmo.fonte
To increase the performance of repeated string concatenation, a Java compiler _may_ use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
A palavra-chave que pode existir em maio . Dado que isso é oficialmente opcional (embora provavelmente implementado), não devemos nos proteger?A chave é se você está escrevendo uma única concatenação em um único local ou acumulando-a com o tempo.
Para o exemplo que você deu, não faz sentido usar explicitamente o StringBuilder. (Veja o código compilado para o seu primeiro caso.)
Mas se você estiver construindo uma string, por exemplo, dentro de um loop, use StringBuilder.
Para esclarecer, assumindo que o enormeArray contenha milhares de strings, codifique assim:
desperdiça muito tempo e memória em comparação com:
fonte
result += s;
(no primeiro exemplo)"{a:"+ a + ", b:" + b + ", c: " + c +"}";
Eu prefiro:
... porque é curto e legível.
Eu não otimizaria isso em termos de velocidade, a menos que você o usasse em um loop com uma contagem de repetições muito alta e medisse a diferença de desempenho.
Concordo que, se você precisar gerar muitos parâmetros, esse formulário poderá ficar confuso (como um dos comentários diz). Nesse caso, eu mudaria para uma forma mais legível (talvez usando o ToStringBuilder do apache-commons - retirado da resposta de matt b) e ignoraria o desempenho novamente.
fonte
null
Na maioria dos casos, você não verá uma diferença real entre as duas abordagens, mas é fácil construir um cenário de pior caso como este:
A saída é:
O problema é que + = anexar a uma string reconstrói uma nova string, por isso custa algo linear ao comprimento de suas strings (soma de ambas).
Então - para sua pergunta:
A segunda abordagem seria mais rápida, mas é menos legível e mais difícil de manter. Como eu disse, no seu caso específico, você provavelmente não perceberia a diferença.
fonte
+=
, o exemplo original foi uma sequência de+
que o compilador transforma em uma únicastring.concat
chamada. Seus resultados não se aplicam.Eu também tive um conflito com meu chefe sobre o fato de usar append ou +. Como eles estão usando Append (eu ainda não consigo descobrir como eles dizem toda vez que um novo objeto é criado). Embora eu goste de explicar Michael Borgwardt, eu só queria mostrar uma explicação se alguém realmente precisa saber no futuro.
e desmontagem da classe acima sai como
Dos dois códigos acima, você pode ver que Michael está certo. Em cada caso, apenas um objeto SB é criado.
fonte
Desde o Java 1.5, a concatenação simples de uma linha com "+" e StringBuilder.append () gera exatamente o mesmo bytecode.
Portanto, para facilitar a leitura do código, use "+".
2 exceções:
fonte
Usando a versão mais recente do Java (1.8), a desmontagem (
javap -c
) mostra a otimização introduzida pelo compilador.+
tambémsb.append()
irá gerar um código muito semelhante. No entanto, vale a pena inspecionar o comportamento se estivermos usando+
um loop for.Adicionando strings usando + em um loop for
Java:
ByteCode :(
for
trecho de loop)Adicionando strings usando stringbuilder.append
Java:
ByteCdoe :(
for
trecho do loop)Há um pouco de diferença gritante embora. No primeiro caso, onde
+
foi usado, novoStringBuilder
é criado para cada iteração de loop e o resultado gerado é armazenado fazendo umatoString()
chamada (29 a 41). Então você está gerando Strings intermediárias que você realmente não precisa enquanto usa o+
operador emfor
loop.fonte
No Java 9, a versão 1 deve ser mais rápida porque é convertida em
invokedynamic
chamada. Mais detalhes podem ser encontrados no JEP-280 :fonte
Por motivos de desempenho, o uso de
+=
(String
concatenação) é desencorajado. O motivo é: JavaString
é imutável, toda vez que uma nova concatenação é feita, uma novaString
é criada (a nova tem uma impressão digital diferente da mais antiga já existente no pool de String ). A criação de novas strings pressiona o GC e diminui a velocidade do programa: a criação de objetos é cara.O código abaixo deve torná-lo mais prático e claro ao mesmo tempo.
Os resultados de uma corrida são relatados abaixo.
Sem considerar os resultados de 1 concatenação (o JIT ainda não estava fazendo seu trabalho), mesmo em 10 concatenações, a penalidade de desempenho é relevante; para milhares de concatenações, a diferença é enorme.
Lições aprendidas com esse experimento muito rápido (facilmente reproduzível com o código acima): nunca use o
+=
para concatenar seqüências de caracteres juntas, mesmo em casos muito básicos em que algumas concatenações são necessárias (como dito, criar novas cadeias de caracteres é caro de qualquer maneira e pressiona o GC).fonte
Veja o exemplo abaixo:
Resultado:
À medida que o comprimento da cadeia aumenta, o tempo de concatenação também aumenta.
É aí que
StringBuilder
definitivamente é necessário.Como você vê, a concatenação:,
UUID.randomUUID()+"---"
realmente não afeta o tempo.PS: Eu não acho que quando usar o StringBuilder em Java seja realmente uma duplicata disso.
Esta pergunta fala sobre o
toString()
que na maioria das vezes não executa concatenações de grandes seqüências de caracteres.Atualização de 2019
Desde os
java8
tempos, as coisas mudaram um pouco. Parece que agora (java13), o tempo de concatenação de+=
é praticamente o mesmo questr.concat()
. No entanto, oStringBuilder
tempo de concatenação ainda é constante . (A postagem original acima foi ligeiramente editada para adicionar uma saída mais detalhada)É importante notar que a
bytecode:8/java.version:13
combinação tem um bom benefício de desempenho em comparação combytecode:8/java.version:8
fonte
java13
quais agora são diferentes. Mas acho que a principal conclusão permanece a mesma.O Apache Commons-Lang possui uma classe ToStringBuilder que é super fácil de usar. Ele faz um bom trabalho manipulando a lógica de acréscimo, bem como a formatação de como você deseja que o seu toString pareça.
Retornará a saída que parece
com.blah.YourClass@abc1321f[a=whatever, b=foo]
.Ou de uma forma mais condensada usando encadeamento:
Ou se você quiser usar a reflexão para incluir todos os campos da classe:
Você também pode personalizar o estilo do ToString, se desejar.
fonte
Torne o método toString o mais legível possível!
A única exceção para isso no meu livro é se você puder provar que consome recursos significativos :) (Sim, isso significa criação de perfil)
Observe também que o compilador Java 5 gera código mais rápido que a abordagem "StringBuffer" manuscrita usada nas versões anteriores do Java. Se você usar "+", este e os aprimoramentos futuros serão gratuitos.
fonte
Parece haver algum debate sobre se o uso do StringBuilder ainda é necessário nos compiladores atuais. Então pensei em dar meus 2 centavos de experiência.
Tenho um
JDBC
conjunto de resultados de 10 mil registros (sim, preciso de todos eles em um lote.) O uso do operador + leva cerca de 5 minutos na minha máquinaJava 1.8
. UsandostringBuilder.append("")
leva menos de um segundo para a mesma consulta.Então a diferença é enorme. Dentro de um loop
StringBuilder
é muito mais rápido.fonte
A concatenação de String em termos de desempenho usando '+' é mais cara porque precisa fazer uma cópia totalmente nova de String, já que Strings são imutáveis em java. Isso desempenha um papel particular se a concatenação for muito frequente, por exemplo: dentro de um loop. A seguir, o que minha IDEA sugere quando tento fazer uma coisa dessas:
Regras gerais:
Aqui está um bom blog de Jon Skeet sobre esse tópico.
fonte
Posso salientar que, se você vai repetir uma coleção e usar o StringBuilder, pode consultar o Apache Commons Lang e o StringUtils.join () (em diferentes tipos)?
Independentemente do desempenho, você economizará a necessidade de criar StringBuilders e de loops pela milionésima vez.
fonte
Aqui está o que eu verifiquei em Java8
Usando StringBuilder
fonte
Eu acho que devemos seguir a abordagem de acréscimo de StringBuilder. Razão de ser:
A concatenação de String criará um novo objeto de string a cada vez (como String é um objeto imutável), portanto, criará 3 objetos.
Com o construtor String, apenas um objeto será criado [StringBuilder é mutável] e a string adicional será anexada a ele.
fonte
Para cordas simples como essa eu prefiro usar
Em ordem, eu diria que o método preferido de construir uma string é usando StringBuilder, String # concat () e, em seguida, o operador + sobrecarregado. O StringBuilder é um aumento significativo no desempenho ao trabalhar com cadeias grandes, assim como o uso do operador + é uma grande diminuição no desempenho (diminuição exponencialmente grande à medida que o tamanho da cadeia aumenta). O único problema ao usar .concat () é que ele pode lançar NullPointerExceptions.
fonte