Otimização de código

[quote=ViniGodoy][quote=sergiotaborda][quote=ViniGodoy]
No caso do equals, nessa situação específica, você vai ter um processo lijeiramente mais longo, pois serão feitas três comparações. A primeira, testa se a string passada no parâmetro é a própria instância (o que nunca vai ocorrer). A segunda, testa se o objeto passado por parâmetro é realmente um String (o que sempre vai ser). E a terceira, finalmente, testa se o tamanho das Strings bate (o que só será verdade para um string vazio).
[/quote]
Não. “abc” e “def” têm o mesmo length. Só se o tamanho é igual é que se tem que passar a uma analise caracter a caracter. Os outros testes são otimizações. O segundo teste tb teste o null. Nem sempre vai ser uma string
[/quote]

Sérgio, estou falando do teste:

!string.equals("")

Que foi proposto pela Lina, no início do tópico. Não tem absolutamente nada a ver com coleções.

E, como mostrado no código fonte da classe String (está no início do tópico), são feitas 3 comparações, sendo 2 delas desnecessárias.

A primeira, verifica se o objeto recebido no parâmetro e o this são exatamente o mesmo objeto. No caso desse exemplo, as chances disso ocorrer são ridiculamente pequenas.
[/quote]

Sim. Mas vc escreveu “o que nunca vai ocorrer” :stuck_out_tongue: lol
Agora eu entendi que vc estava falando do caso especifico de string.equals(""). Peço desculpas se o ofendi.

Interessante… o

"".equals(s)

Demora mais que o

s.equals("")

Por que isso??

[quote=Foxlol]Com a primeira opção vc estará criando uma String a mais na memória.
Já com a segunda é apenas uma comparação com um tipo primitivo.[/quote]

Foxlol,

Conforme sugere o método java.lang.String#intern(), acredito que no caso específico da String “”, ela já esteja na memória através do pool de Strings mantido pela própria classe, não onerando assim a memória ao instanciar mais um objeto.

[quote=ViniGodoy]O length é mais rápido por se tratar apenas da leitura de um atributo e da comparação no seu if, observe (esses códigos foram retirados da classe String):

public int length() {
        return count;
    }

No caso do equals, nessa situação específica, você vai ter um processo lijeiramente mais longo, pois serão feitas três comparações. A primeira, testa se a string passada no parâmetro é a própria instância (o que nunca vai ocorrer). A segunda, testa se o objeto passado por parâmetro é realmente um String (o que sempre vai ser). E a terceira, finalmente, testa se o tamanho das Strings bate (o que só será verdade para um string vazio).

public boolean equals(Object anObject) {
   if (this == anObject) { //Comparação 1
      return true;
   }
   if (anObject instanceof String) {  //Comparação 2
      String anotherString = (String)anObject;    
      int n = count;
      if (n == anotherString.count) {    //Comparação 3
         char v1[] = value;
         char v2[] = anotherString.value;
         int i = offset;
         int j = anotherString.offset;
         while (n-- != 0) {
            if (v1[i++] != v2[j++])
               return false;
      }
      return true;
   }
}
	return false;
    }

Usando o equals é ainda mais recomendado colocar a constante na frente, assim:

if (!"".equals(string))

Isso dá uma vantagem adicional, pois o código também falha caso a string seja nula. Nos seus exemplos, você acabaria com um NullPointerException.

Agora, não creio que isso seja otimização de código, a menos que você esteja num loop realmente intenso, comparando milhares de Strings por segundo. Provavelmente haverá outros locais muito piores na sua aplicação. Não adianta “otimizar” pontos fora desses gargalos. Você só aumentará o tempo ocioso do sistema, que espera o gargalo passar. Sempre que se falar em otimização, rode um profiler, como o do Netbeans, e identifique os pontos de baixa performance. Otimize apenas esses pontos.

Otimização tem um custo: ela torna o código mais complexo e muito menos flexível. E deve ser uma preocupação apenas nos momentos de projeto e nos pontos críticos identificados no código.[/quote]

ViniGodoy,

Conforme falei acima, se vc olhar o javadoc do método java.lang.String#intern(), a primeira comparação se faz necessária, pois o objeto pode estar no pool de Strings mantido pela própria classe.

Quanto a vc afirmar que a segunda comparação tbm será sempre verdadeira, tbm discordo… O método equals espera um Object, então qualquer coisa pode ser passada e em um projeto com muitos estagiários você pode ver a invocação do método equals de uma String recebendo como parâmetro um Double, por exemplo.

Já a terceira comparação não entendi pq vc afirmou ser possível somente para String vazia.

Observe que falei que é “nessa situação específica”. Ele estava querendo testar se uma string era vazia através da comparação “”.equals(string) - Aliás, isso também é explicado para o sergio taborda bem no início do post onde vc fez quote.

No caso dessa comparação é muitíssimo raro que a string recebida seja igual idêntica a String vazia (passe no ==). O método intern pode garantir isso, mas ele também exige custo computacional, e muito maior que o do equals. Como ele também disse que passaria uma string por parâmetro, sabíamos que não se tratava de outra classe.

É por isso mesmo que o método equals é mais lento que o length para testar String vazia. Por que ele:
a) Se previne contra o uso incorreto (já que pode receber um object);
b) Testa se os objetos são idênticos (o que normalmente não vai ocorrer).

No caso, o length não precisa fazer nada disso.

Em todo caso, desde o Java 6, essa dúvida já não existe mais. Inseriram o método isEmpty() na classe String. Por isso que não é muito saudável ressuscitar discussões de 2008. E, lógico, sua implementação baseia-se no length().

Não estou falando que a implementação do equals é errada. Na verdade, esses fatores são otimizações para quando se quer testar se duas strings são iguais. Porém, isso não quer dizer que elas sejam eficientes para testar o vazio. E, como eu já disse outras vezes no tópico, a diferença de 1 if para 3 ifs em termos de performance é apenas acadêmica pois, na prática, dificilmente isso aí constituirá um gargalo de performance em qualquer aplicação comercial.