Bom, estou lendo o Livro da Kathy e acabei com uma duvida sobre string.
String palavra = "nome"; //Cria um objeto string que é colocado no constant pool string (se não me engano é esse o nome)
String palavraB = new String("sobrenome"); //Cria dois objetos Strings, um no pool e um no heap
no livro no exemplo so muda o nome das variaveis e strings.
é isso mesmo?
e outra duvida
String nome = "Silvio"; //Criei um string no pool
String sobrenome = nome.concat(" Lucena"); //Criei um objeto string no pool " Lucena" e o objeto string no pool
//"Silvio Lucena"
String nomeCompleto = sobrenome + " Junior" //Criei mais dois objetos strings no pool (Junior e Silvio Lucena Junior)
total: 5 objetos string no pool e 2 deles referenciados
é isso mesmo? estou certo?
existe diferença entre o
String sobrenome = nome.concat(" Lucena");
e o
String sobrenome = nome.+ " Lucena";
???
Cara, sobre a pergunta nem consigo te responder… mas ja li a respeito que nem se usa o tipo String ( so para programinhas que nem a gente faz… ) , usa-se outras duas classes, se alguem tiver mais informação pro cara…
Abraços
Fiz aqui um tester para poder ver melhor como a coisa funciona:
public class StringTester {
public static void main(String[] args) {
int iterations = 10000000;
long time = 0;
System.out.println();
System.out.println("String Tester");
System.out.println();
System.out.println("Test 1");
System.out.println("----------------------------------------");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
String s = "test" + " 123" + "!!!";
}
System.out.println("Plus = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
String s = "test".concat(" 123").concat("!!!");
}
System.out.println("Concat = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
String s = new StringBuffer("test").append(" 123").append("!!!").toString();
}
System.out.println("StringBuffer = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
String s = new StringBuilder("test").append(" 123").append("!!!").toString();
}
System.out.println("StringBuilder = " + (System.currentTimeMillis() - time) + "ms");
System.out.println("----------------------------------------");
System.out.println();
System.out.println("Test 2");
System.out.println("----------------------------------------");
time = System.currentTimeMillis();
String sp = "test";
for (int x = 0; x < iterations; x++) {
String s = sp + " 123" + "!!!";
}
System.out.println("Plus = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
String sc = "test";
for (int x = 0; x < iterations; x++) {
String s = sc.concat(" 123").concat("!!!");
}
System.out.println("Concat = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
StringBuffer sbf = new StringBuffer("test");
for (int x = 0; x < iterations; x++) {
String s = sbf.append(" 123").append("!!!").toString();
sbf.setLength(0);
}
System.out.println("StringBuffer = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
StringBuilder sbl = new StringBuilder("test");
for (int x = 0; x < iterations; x++) {
String s = sbl.append(" 123").append("!!!").toString();
sbl.setLength(0);
}
System.out.println("StringBuilder = " + (System.currentTimeMillis() - time) + "ms");
System.out.println("----------------------------------------");
System.out.println();
}
}
Resultado:
String Tester
Test 1
----------------------------------------
Plus = 31ms
Concat = 2579ms
StringBuffer = 6064ms
StringBuilder = 5063ms
----------------------------------------
Test 2
----------------------------------------
Plus = 5064ms
Concat = 2594ms
StringBuffer = 2735ms
StringBuilder = 2532ms
----------------------------------------
Moral da história… o Concat é mais fácil e mais rápido…
Por que você está chamando delete usando o StringBuilder e o StringBuffer?
Com uma operação a mais a cada loop, vai dar mais lento mesmo!
[quote=ViniGodoy]Por que você está chamando delete usando o StringBuilder e o StringBuffer?
Com uma operação a mais a cada loop, vai dar mais lento mesmo![/quote]
Mudei o delete para setLength e da no mesmo… entao como resetar para usar o mesmo objeto???
E se o StringBuilder/StringBuffer estivesse dentro de um método chamado apartir do loop, seria criado N objetos a mais como demonstrado no primeiro exemplo, uma grande perda de performance, então o concat passa a ser o ideal a ser usado, ou não?
Creio q o concat em todos os casos vai se sair bem… sendo assim devemos usar o concat em vez do StringBuffer/StringBuilder? Sempre?
No caso do String Builder / Buffer você está medindo não só o tempo da concatenação, mas também o tempo que ele leva para instanciar um objeto String no final. E é justamente esse tempo que se ganha ao utiliza-lo.
Teste outro benchmark concatenando 123 !!! várias vezes numa mesma string e só ao final gerando o resultado com toString() (que é como se normalmente se trabalha com o StringBuilder e StringBuffer). Talvez você obtenha resultados diferentes.
Não seja tão apressado ao concluir coisas baseado em resultados de microbenchmarks já que, assim como o seu, muitos expressam só parcialmente o que ocorre na realidade (ou não expressam nada). Benchmarks como esse também levam em pouca consideração caches e compilações hotspot feitas pela VM.
O que o seu benchmark nos leva a concluir é que, para pequenas concatenações, o sinal de + é o mais rápido, seguido pelo concat. Mas será que isso seria válido para as grandes concatenações?
Veja só um exemplo.
Passei o StringBuilder para primeiro na ordem de execução e obtive os seguintes resultados:
Test 1
StringBuilder = 2594ms
Plus = 15ms
Concat = 1922ms
StringBuffer = 4719ms
Test 2
StringBuilder = 1781ms
Plus = 2610ms
Concat = 1890ms
StringBuffer = 2078ms
Test 1
StringBuilder = 2593ms
Plus = 0ms
Concat = 1922ms
StringBuffer = 4766ms
Test 2
StringBuilder = 1812ms
Plus = 2610ms
Concat = 1875ms
StringBuffer = 2234ms
Que tipo de maluquice será que a VM faz por trás de tudo?!? O seu resultado também mostra uma discrepancia. Como você pode concluir a respeito do concat com a aquela variação enorme no tempo do plus? Essa variação pode ter ocorrido em todos os seus resultados, afetando todo o tempo do teste.
Isso provavelmente é o garbage collector e outros mecanismos da VM rodando.
Mas não superou o concat…
Eu estou fazendo um novo benchmark com uma concatenação maior, e no primeiro teste mesmo o StringBuilder e o StringBuffer sendo criados varias vezes ja foram muito mais rapido…
Quando acabar o teste posto aqui o codigo e o resultado… é q esta demorando o segundo teste
Pronto… agora sim… tive q baixar os valores por q estava demorando muitooo:
public class StringTester {
public static void main(String[] args) {
int iterations = 100;
int subiterations = 100;
long time = 0;
System.out.println();
System.out.println("String Tester");
System.out.println();
System.out.println("Test 1");
System.out.println("----------------------------------------");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
String s = "";
for (int y = 0; y < subiterations; y++) {
s += "test" + " 123" + "!!!";
}
}
System.out.println("Plus = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
String s = "";
for (int y = 0; y < subiterations; y++) {
s = s.concat("test").concat(" 123").concat("!!!");
}
}
System.out.println("Concat = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
StringBuffer s = new StringBuffer();
for (int y = 0; y < subiterations; y++) {
s.append("test").append(" 123").append("!!!");
}
}
System.out.println("StringBuffer = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
StringBuilder s = new StringBuilder();
for (int y = 0; y < subiterations; y++) {
s.append("test").append(" 123").append("!!!");
}
}
System.out.println("StringBuilder = " + (System.currentTimeMillis() - time) + "ms");
System.out.println("----------------------------------------");
System.out.println();
System.out.println("Test 2");
System.out.println("----------------------------------------");
time = System.currentTimeMillis();
String sp = "";
for (int x = 0; x < iterations; x++) {
for (int y = 0; y < subiterations; y++) {
sp += "test" + " 123" + "!!!";
}
}
System.out.println("Plus = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
String sc = "";
for (int x = 0; x < iterations; x++) {
for (int y = 0; y < subiterations; y++) {
sc = sc.concat("test").concat(" 123").concat("!!!");
}
}
System.out.println("Concat = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
StringBuffer sbf = new StringBuffer();
for (int x = 0; x < iterations; x++) {
for (int y = 0; y < subiterations; y++) {
sbf.append("test").append(" 123").append("!!!");
}
}
System.out.println("StringBuffer = " + (System.currentTimeMillis() - time) + "ms");
time = System.currentTimeMillis();
StringBuilder sbl = new StringBuilder("test");
for (int x = 0; x < iterations; x++) {
for (int y = 0; y < subiterations; y++) {
sbl.append("test").append(" 123").append("!!!");
}
}
System.out.println("StringBuilder = " + (System.currentTimeMillis() - time) + "ms");
System.out.println("----------------------------------------");
System.out.println();
}
}
Resultado:
String Tester
Test 1
----------------------------------------
Plus = 63ms
Concat = 31ms
StringBuffer = 16ms
StringBuilder = 0ms
----------------------------------------
Test 2
----------------------------------------
Plus = 10374ms
Concat = 6734ms
StringBuffer = 16ms
StringBuilder = 31ms
----------------------------------------
Agora é estudar quando usar cada um em cada caso explorando o ponto forte…
O q me espanta é o StringBuilder ter sido mais rápido no primeiro caso…?!
ok… fiz outros testes… e o:
StringBuffer = 16ms
StringBuilder = 31ms
Não podem ser levados em consideração… é o mesmo q Zero claro
Mudei um pouco o programa:
[code]public class StringTester {
public static void main(String[] args) {
int iterations = 20000;
long time = 0;
System.out.println();
System.out.println(“String Tester”);
String s = “”;
for (int i = 0; i < 2; i++)
{
System.out.println();
System.out.println(“Test " + i);
System.out.println(”----------------------------------------");
StringBuilder sbuilder = new StringBuilder();
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
sbuilder.append("abc").append(" 123").append("!!!").toString();
}
s = sbuilder.toString();
System.out.println("StringBuilder = " + (System.currentTimeMillis() - time) + "ms");
s = "";
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
s += "cde" + " 456" + "...";
}
System.out.println("Plus = " + (System.currentTimeMillis() - time) + "ms");
s = "";
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
s = s.concat("efg").concat(" 789").concat("???");
}
System.out.println("Concat = " + (System.currentTimeMillis() - time) + "ms");
s = "";
StringBuffer sb = new StringBuffer();
time = System.currentTimeMillis();
for (int x = 0; x < iterations; x++) {
sb.append("hij").append(" lmn").append("***").toString();
}
s = sb.toString();
System.out.println("StringBuffer = " + (System.currentTimeMillis() - time) + "ms");
System.out.println("----------------------------------------");
System.out.println();
}
}
}
[/code]
Agora concateno coisas diferentes, de mesmo tamanho. Assim ninguém se beneficia de strings internalizadas no pool.
Os resultados já foram mais consistentes:
Test 1
StringBuilder = 2344ms
Plus = 17609ms
Concat = 19204ms
StringBuffer = 2343ms
Test 2
StringBuilder = 2328ms
Plus = 13500ms
Concat = 19360ms
StringBuffer = 2344ms
Quer tentar rodar no seu também (além de conferir o código)? Acho que estamos conseguindo filtrar parte do ruído.
exato, deu o dobro
StringBuilder = 4234ms
Plus = 69749ms
Concat = 31203ms
StringBuffer = 4297ms
Bem mas isto é concatenação grande, concatenação curta, continua sendo o problema.
Se tenho um método q cria um StringBuilder e faz uns appends, e depois por acaso alguem chama este método dentro de um loop, e ai como ficamos?
Então sempre q for simples concactenações devemos usar o concat? Que o + só é mais rápido quando são strings estáticas, se tiver uma string como variável ai já é mais demorado que o concat, como no primeiro benchmark.
Certo?
Ou seja se formos fazer um return…
Isto estaria errado:
return new StringBuilder(s).append(".");
Assim é o correto:
return s.concat(".");
Se for duas strings estaticas, o certo é:
return ".." + ".";
Mas no caso de duas strings estaticas não há razão para fazer somas lol
E tudo q for concatenações massivas sempre StringBuilder e em problemas especificos de sincronismo o StringBuffer.
De acordo?
De acordo. De qualquer forma, a experiência foi interessante.
Ainda assim, a dica da Sun é válida:
Na dúvida use StringBuilder.
Em poucas concatenações curtas, a diferença de tempo não será significativa. (Afinal, elas são curtas mesmo)
Numa longa, a performance dele é muito melhor.
Claro, se você souber que existe uma série de concatenações curtas, especialmente se for baseada em valores parecidos, aí pode usar o concat.
Mas é sempre bom saber dessas diferenças.
E a moral da história. Não se apressar em concluir coisas com benchmarks. O ideal é ficar atentos a diferença muito grandes de número e valores, especialmente entre 2 ou 3 execuções. Essas diferenças geralmente indicam ruídos (garbage collection, alocação de memória, etc) que tem que ser filtrados.
ya foi uma boa experiência!
sim, mais bom senso nos benchmarks pra próxima, vou tentar
e isto de usar o concat ou StringBuilder, já vi muita gente dizendo e fazendo new StringBuilder pra tudo e mais um pouco e eu tb já fiz muito isso, e sempre fiquei com a pulga atrás da orelha em usar StringBuilder sempre.
valew a experiência, agora esta tudo mais claro