compareTo vs equals
Publicado en Java el 20 de March, 2009 por Lek.Al actualizar el código de un proyecto antiguo uno se puede encontrar cualquier cosa. En una de esas paranoias mías (o eso creía yo) me dio por dedicarme a cambiar todos los compareTo por equals, que me parecía como una instrucción más directa, óptima y mejor. No iba yo muy desencaminado.
La primera nos devuelve un entero que indica si el objeto es mayor que el parámetro de entrada, menor, o igual. La segunda nos devuelve directamente un booleano que nos dice si son iguales o no. Pero yo personalmente no recuerdo haber utilizado nunca el compareTo para algo que no fuera comprobar si un objeto (y más en concreto un String) es igual a otro. Así pues, me he creado un código chorras para saber cuánta diferencia hay (de paso metí el equalsIgnoreCase):
public static void main (String [] args) {
String s = "necesito una prueba a ver si cuela ésta misma";
long ini = System.nanoTime ();
for (int i = 0 ; i < 10000000; i ++ ) {
boolean b = s.compareTo ("necesito una prueba") == 0;
}
System.out.println (
"CompareTo: " + (System.nanoTime () - ini)/1000000.0);
ini = System.nanoTime ();
for (int i = 0 ; i < 10000000; i ++ ) {
boolean b = s.equals ("necesito una prueba");
}
System.out.println (
"equals: " + (System.nanoTime () - ini)/1000000.0);
ini = System.nanoTime ();
for (int i = 0 ; i < 10000000; i ++ ) {
boolean b = s.equalsIgnoreCase ("necesito una prueba");
}
System.out.println (
"equalsIgnoreCase: " + (System.nanoTime () - ini) /1000000.0);
}
Los resultados son demoledores. compareTo es unas 150 veces más lento que equals:
(el tiempo va en milisegundos)
CompareTo: 1886.853143
equals: 71.728111
equalsIgnoreCase: 60.81111
Sorprende que equalsIgnoreCase sea más rápido que equals, sobre todo porque lo primero que hace es ejecutar el equals. Puede ser cosa del orden, pero probando a cambiarlas los datos no variaban demasiado. Sí puedo decir que de tanto en tanto equals es más rápido. En cualquier caso, puede parecer una chorrada perder 1'8 segundos en 10 millones de consultas que no se van a dar así en un programa real, pero al final todo suma y si los Strings ya son poco óptimos de por sí...
¿Dónde probaste esto? Porque lo he probado ahora mismo en el trabajo, y me salen tiempos totalmente diferentes:
Mi máquina es un AMD Athlon(tm) 64 X2 Dual Core Processor 3800+ con 4 GB de RAM, utilizo Debian y la versión 1.6.0.12 de la JVM de Sun.
# Fran 30 de March, 2009
Ahora mismo. En un WinXP de un Dell a 3.19GHz con 2 gigas de RAM. Desde Eclipse, con el JDK 1.6.0_06…
# Lek 2 de April, 2009
Pues tío, es una diferencia muy grande, intenta probarlo sin eclipse y con el JDK que te dicho que he usado, sólo por curiosidad, que ya me tiene intrigado.
# Fran 2 de April, 2009
Compilado desde línea de comandos, ejecutado desde línea de comandos… he cambiado el orden y metido en un bucle de 10 iteraciones:
Eso sí, el mismo JDK 6…06. Curioso, curioso…
# Lek 2 de April, 2009
Pues sí, es muy raro, yo no sé si es Linux, los 64 bits o el JDK. En principio daría igual la arquitectura y el sistema operativo, ya que para eso está la JVM, por eso me resulta curioso.
# Fran 2 de April, 2009
Con Java 5 me salen mejores resultados para compareTo… pero con el último JDK me salen prácticamente iguales. Será el Windows… es la única alternativa…
# Lek 2 de April, 2009
¡Maldito Windows! xD
# Fran 2 de April, 2009
lek creo que te pelaste en el calculo, segun tu prueba compareTo no es 150 veces mas lento sino 27 aprox.
la clase String sobreescribe el metodo equals y realiza la comparacion caracter por caracter, como tambien lo hace compareTo, lo que hace aun mas extraño el resultado!
String.equals(String) entonces deberia hacer una comparacion mas que compareTo para retornar el booleano
# samuel 5 de May, 2009
bueno tambien probé el codigo pero calculando la demora en segundos, acá los resultados:
compareTo 1.914529639
equals 0.157562256
ini-actual: 0.134674135
# samuel 5 de May, 2009
sorry por el post anterior, lo publiqué incompleto sin querer, los resultados fueron en segundos:
compareTo
1.914529639
equals
0.157562256
equalsIgnore
0.134674135
en java 1.6, en ubuntu 9.04.
tambien resulto mas rapido equals, como que no era windows(no esta vez jaja)
# samuel 5 de May, 2009
Samuel, gracias por la aclaración sobre las diferencias… (¿nadie más lo vio?). En cualquier caso, veo que también te da más rápido el
equals(incluso elequalsIgnoreCase), lo cual hace las cosas aún más extrañas :-/# Lek 5 de May, 2009
Ps a mi me salió esto con el código que tienes al inicio:
CompareTo: 472.068861
equals: 69.260289
equalsIgnoreCase: 69.272754
Utilicé la línea de comandos y con JDK 1.6 en un Pentium Dual Core a 2.5 GHz con 2 GB de RAM y Windows XP SP3
# Luis 23 de September, 2009
Haber , yo creo que es mejor usar equals por motivos de performance , yo siempre lo he usado en cualquier sistema windows , linux , solaris , bueno solo es mi opinion
String cadena=”hola mundo”;
if(cadena.compareTo(“hola”) == 0){
//yo creo que aca se hacen 2 comprobaciones
}
if(cadena.equals(“hola”)){
//yo creo que aca se hace 1 comprobacion
}
# vegeta 10 de February, 2010
Creo que hoy voy a dar el premio al comentario tonto del blog, vegeta en el código que has puesto en las dos condiciones se hacen dos comprobaciones:
compareToy la del igual a cero, esta está clara.equalsy la que tiene que hacer elifpara saber si el resultado delequalses verdadero o falso, sino ¿cómo sabe si tiene que entrar?PD: Es a ver, no haber.
# Fran 15 de February, 2010