compareTo () vs. equals ()

118

Al probar la igualdad de Stringen Java, siempre lo he usado equals()porque para mí este parece ser el método más natural para hacerlo. Después de todo, su nombre ya dice lo que se pretende hacer. Sin embargo, un colega mío me dijo recientemente que me habían enseñado a usar en compareTo() == 0lugar de equals(). Esto me parece antinatural (ya que compareTo()está destinado a proporcionar un orden y no comparar por igualdad) e incluso algo peligroso (porque compareTo() == 0no implica necesariamente igualdad en todos los casos, aunque sé que sí lo hace String) para mí.

No sabía por qué le enseñaron a usar en compareTo()lugar de equals()para String, y tampoco pude encontrar ninguna razón por la cual. ¿Es esto realmente una cuestión de gusto personal o hay alguna razón real para cualquiera de los métodos?

Thomas Lötzer
fuente
9
Estrictamente hablando a un nivel de microoptimización, del que nunca deberíamos hablar prematuramente, .equalsIgnoreCase()es la comparación más rápida si es apropiada, de lo contrario .equals()es lo que quieres.
1
Esta es una pregunta antigua, pero contiene una pepita que quería resaltar: " compareTo() == 0no implica necesariamente igualdad en todos los casos". ¡Esto es absolutamente correcto! Esto es exactamente lo que significa la frase "coherente con iguales" en las especificaciones de la API de Java, por ejemplo, en la especificación de clase Comparable . Por ejemplo, el método de comparación de String es consistente con equals, pero el método de comparación de BigDecimal es inconsistente con equals.
Stuart Marks

Respuestas:

104

Una diferencia es que "foo".equals((String)null)devuelve falso mientras "foo".compareTo((String)null) == 0arroja una NullPointerException. Por lo que no siempre son intercambiables incluso para Strings.

ala de cera
fuente
6
Creo que también deberías mencionar esto. es igual a calcula el código hash. El código hash de dos cadenas diferentes, aunque poco común, puede ser el mismo. Pero cuando usa compareTo (), verifica las cadenas carácter por carácter. Entonces, en este caso, dos cadenas devolverán verdadero si y solo si sus contenidos reales son iguales.
Ashwin
30
¿Por qué crees que es igual a calcular el código hash? Puede ver que este no es el caso: docjar.com/html/api/java/lang/String.java.html (línea 1013).
Waxwing
3
tienes razón. Pensé que equals y hashcode van de la mano (equals comprueba si ambos tienen el mismo código hash). Entonces, ¿por qué es necesario anular ambos métodos si decide anular alguno de ellos?
Ashwin
3
Es necesario anular el código hash cuando anulamos los iguales porque si la clase usa colecciones basadas en hash, incluidos HashMap, HashSet y Hashtable, la clase no funcionará correctamente
varunthacker
4
@Ashwin Es necesario porque si .equals devuelve verdadero, los códigos hash también deberían ser iguales. Sin embargo, si los códigos hash son iguales, no implica que .equals deba devolver verdadero
Alan
33

Las 2 principales diferencias son que:

  1. equalstomará cualquier objeto como parámetro, pero compareTosolo tomará cadenas.
  2. equalssolo le dice si son iguales o no, pero compareTobrinda información sobre cómo las cadenas se comparan lexicográficamente.

Eché un vistazo al código de la clase String , y el algoritmo dentro de compareTo and equals se ve básicamente igual. Creo que su opinión fue solo una cuestión de gustos, y estoy de acuerdo contigo: si todo lo que necesitas saber es la igualdad de las cuerdas y no cuál viene primero lexicográficamente, entonces la usaría equals.

Kaleb Brasee
fuente
26

Al comparar por igualdad, debe usar equals(), porque expresa su intención de una manera clara.

compareTo() tiene el inconveniente adicional de que solo funciona en objetos que implementan la Comparable interfaz.

Esto se aplica en general, no solo a Strings.

estrella azul
fuente
18

compareTotiene que hacer más trabajo si las cadenas tienen diferentes longitudes. equalssolo puede devolver falso, mientras compareToque siempre debe examinar suficientes caracteres para encontrar el orden de clasificación.

robinr
fuente
10

compareTo()no solo se aplica a Strings sino también a cualquier otro objeto porque compareTo<T>toma un argumento genérico T. String es una de las clases que ha implementado el compareTo()método implementando la Comparableinterfaz. (compareTo () es un método para la interfaz comparable). Entonces, cualquier clase es libre de implementar la interfaz Comparable.

Pero compareTo()da el orden de los objetos , que se usa típicamente para clasificar objetos en orden ascendente o descendente, mientras equals()que solo hablará de la igualdad y dirá si son iguales o no.

apurva jadhav
fuente
10

En contexto de cadena:
compareTo: Compara dos cadenas lexicográficamente.
es igual a: compara esta cadena con el objeto especificado.

compareTo compara dos cadenas por sus caracteres (en el mismo índice) y devuelve un número entero (positivo o negativo) en consecuencia.

String s1 = "ab";
String s2 = "ab";
String s3 = "qb";
s1.compareTo(s2); // is 0
s1.compareTo(s3); // is -16
s3.compareTo(s1); // is 16
VirtualLogic
fuente
7

equals () puede ser más eficiente que compareTo () .

Una diferencia muy importante entre compareTo y equals:

"myString".compareTo(null);  //Throws java.lang.NullPointerException
"myString".equals(null);     //Returns false

equals () comprueba si dos objetos son iguales o no y devuelve un valor booleano.

compareTo () (de la interfaz Comparable) devuelve un número entero. Comprueba cuál de los dos objetos es "menor que", "igual a" o "mayor que" el otro. No todos los objetos pueden ordenarse lógicamente, por lo que un método compareTo () no siempre tiene sentido.

Tenga en cuenta que equals () no define el orden entre objetos, lo que hace compareTo ().

Ahora le aconsejo que revise el código fuente de ambos métodos para concluir que es preferible igual a compareTo que implica algunos cálculos matemáticos.

Jaimin Patel
fuente
5

Parece que ambos métodos hacen prácticamente lo mismo, pero el método compareTo () toma un String, no un Object, y agrega alguna funcionalidad adicional además del método equals () normal. Si todo lo que le importa es la igualdad, entonces el método equals () es la mejor opción, simplemente porque tiene más sentido para el próximo programador que eche un vistazo a su código. La diferencia de tiempo entre las dos funciones diferentes no debería importar a menos que esté recorriendo una gran cantidad de elementos. CompareTo () es realmente útil cuando necesita conocer el orden de las cadenas en una colección o cuando necesita conocer la diferencia de longitud entre cadenas que comienzan con la misma secuencia de caracteres.

fuente: http://java.sun.com/javase/6/docs/api/java/lang/String.html

Scott M.
fuente
5

equals() debe ser el método de elección en el caso del PO.

Al observar la implementación de equals()y compareTo()en java.lang.String en grepcode , podemos ver fácilmente que igual es mejor si solo nos preocupa la igualdad de dos cadenas:

equals():

1012   public  boolean equals ( Object anObject) { 
1013 if ( this == anObject) {
1014 return true ;
1015 }
1016 if ( instancia de un objeto de cadena ) {
1017 Cadena otra cadena = ( cadena ) un objeto;
1018 int n = cuenta;
1019 if (n == anotherString.count) {
1020 char v1 [] = valor;
1021 char v2 [] = anotherString.value;
1022 int i = desplazamiento;
1023 int j = anotherString.offset;
1024 while (n--! = 0) {
1025 if (v1 [i ++]! = V2 [j ++])
1026 return false ;
1027 }
1028 devuelve verdadero ;
1029 }
1030 }
1031 return false ;
1032 }

y compareTo():

1174   public  int compareTo ( String anotherString) { 
1175 int len1 = count;
1176 int len2 = anotherString.count;
1177 int n = Matemáticas. min (len1, len2);
1178 char v1 [] = valor;
1179 char v2 [] = anotherString.value;
1180 int i = desplazamiento;
1181 int j = anotherString.offset;
1183 si (i == j) {
1184 int k = i;
1185 int lim = n + i;
1186 mientras (k <lim) {
1187 1194 } else { 1195 while (n--! = 0) { 1196 char c1 = v1 [i ++]; 1197 carácter c2 = v2 [j ++]; 1198 if (c1! = C2) { 1199 return c1 - c2; 1200 } 1201 } 1202 } 1203 char c1 = v1 [k];
1188 Char c2 = v2 [k];
1189 if (c1! = C2) {
1190 return c1 - c2;
1191 }
1192 k ++;
1193 }









return len1 - len2;
1204 }

Cuando una de las cadenas es un prefijo de otra, el rendimiento de compareTo()es peor, ya que aún necesita determinar el orden lexicográfico mientras equals()no se preocupa más y devuelve falso inmediatamente.

En mi opinión, deberíamos usar estos dos como estaban destinados:

  • equals() para comprobar la igualdad, y
  • compareTo() para encontrar el orden léxico.
prk
fuente
3

equals () comprueba si dos cadenas son iguales o no y da un valor booleano. compareTo () comprueba si el objeto de cadena es igual, mayor o menor que el otro objeto de cadena. Da el resultado como: 1 si el objeto de cadena es mayor 0 si ambos son iguales -1 si la cadena es más pequeña que otra cadena

eq:

String a = "Amit";
String b = "Sumit";
String c = new String("Amit");
System.out.println(a.equals(c));//true
System.out.println(a.compareTo(c)); //0
System.out.println(a.compareTo(b)); //1
Ankit Uniyal
fuente
2

Hay ciertas cosas que debe tener en cuenta al anular compareTo en Java, por ejemplo, Compareto debe ser consistente con iguales y la resta no debe usarse para comparar campos enteros, ya que pueden desbordarse. consulte Cosas para recordar al anular Comparator en Java para obtener más detalles.

Seema Kiran
fuente
2

Este es un experimento de nigromancia :-)

La mayoría de las respuestas comparan el rendimiento y las diferencias de API. Se pierden el punto fundamental de que las dos operaciones simplemente tienen una semántica diferente.

Tu intuición es correcta. x.equals (y) no es intercambiable con x.compareTo (y) == 0. El primero compara la identidad, mientras que el otro compara la noción de 'tamaño'. Es cierto que en muchos casos, especialmente con los tipos primitivos, estos dos co-alinean.

El caso general es este:

Si xey son idénticos, comparten el mismo 'tamaño': si x.equals (y) es verdadero => x.compareTo (y) es 0.

Sin embargo, si xey comparten el mismo tamaño, no significa que sean idénticos.

si x.compareTo (y) es 0 no significa necesariamente que x.equals (y) sea verdadero.

Un ejemplo convincente en el que la identidad difiere del tamaño serían los números complejos. Suponga que la comparación se realiza por su valor absoluto. Entonces, dados dos números complejos: Z1 = a1 + b1 * i y Z2 = a2 + b2 * i:

Z1.equals (z2) devuelve verdadero si y solo si a1 = a2 y b1 = b2.

Sin embargo, Z1.compareTo (Z2) devuelve 0 para un número infinito de pares (a1, b1) y (a2, b2) siempre que satisfagan la condición a1 ^ 2 + b1 ^ 2 == a2 ^ 2 + b2 ^ 2.

Vitalidad
fuente
1
x.equals (y) no significa Identidad, significa Igualdad. La identidad se compara usando x == y para tipos definidos por el usuario en Java.
Fernando Pelliccioni
2

Equals puede ser más eficiente que compareTo.

Si la longitud de las secuencias de caracteres en String no coincide, no hay forma de que las cadenas sean iguales, por lo que el rechazo puede ser mucho más rápido.

Además, si es el mismo objeto (igualdad de identidad en lugar de igualdad lógica), también será más eficiente.

Si también implementaron el almacenamiento en caché de hashCode, podría ser incluso más rápido rechazar los no iguales en caso de que su hashCode no coincida.

Gopal Rajpurohit
fuente
2

String.equals()requiere invocar al instanceofoperador mientras compareTo()que no lo requiere. Mi colega ha notado un gran menú desplegable de rendimiento causado por un número excesivo de instanceofllamadas en el equals()método, sin embargo, mi prueba ha demostrado compareTo()ser solo un poco más rápida.

Sin embargo, estaba usando Java 1.6. En otras versiones (u otros proveedores de JDK) la diferencia podría ser mayor.

La prueba comparó cada cadena en 1000 matrices de elementos, repetidas 10 veces.

Marinero danubiano
fuente
1
Supongo que debe haber utilizado cadenas muy cortas, todas de la misma longitud y con una gran diversidad en el primer carácter para obtener un resultado ¿dónde compareTo()es más rápido que equals()? Pero para la mayoría de los conjuntos de datos del mundo real equals()es mucho más rápido que compareTo() == 0. equals()brilla si las cadenas tienen un prefijo común pero diferentes longitudes o si en realidad son el mismo objeto.
x4u
Bueno, mi prueba fue contra la hipotesis de que instanceof es un asesino del rendimiento, por lo que las cadenas eran realmente cortas.
Marinero del Danubio
Si su cadena es aleatoria y en su mayoría difieren en longitud, entonces la opción más obvia debería ser el método equals () sobre compareTo () ya que en la mayoría de los casos devolverá falso inmediatamente si no tienen la misma longitud.
Sactiw
1
  1. equalspuede tomar cualquier objeto como parámetro, pero compareTosolo puede tomar String.

  2. cuando llegue a null, compareTolanzará una excepción

  3. cuando quiera saber dónde ocurre la diferencia, puede usar compareTo.

pequeño tigre
fuente
compareTo puede tomar cualquier objeto como argumento. Como dijo anteriormente @apurva jadhav, comparable requiere un argumento genérico. Si implementa comaparable como Comparable <String>, entonces puede usar solo cadenas.
Gaurav Kumar
1
  • equals: requerido para verificar la igualdad y restringir duplicados. Muchas clases de la biblioteca Java usan esto en caso de que quisieran encontrar duplicados. por ejemplo HashSet.add(ob1), solo agregará si eso no existe. Entonces, si está extendiendo algunas clases como esta, anule equals().

  • compareTo: requerido para ordenar el elemento. Nuevamente, para una clasificación estable, necesita igualdad, por lo que hay un retorno 0.

Dillip Rout
fuente
0

Igual a -

1- Anule el método GetHashCode para permitir que un tipo funcione correctamente en una tabla hash.

2- No arroje una excepción en la implementación de un método Equals. En su lugar, devuelva falso para un argumento nulo.

3-

  x.Equals(x) returns true.

  x.Equals(y) returns the same value as y.Equals(x).

  (x.Equals(y) && y.Equals(z)) returns true if and only if x.Equals(z) returns true.

Las sucesivas invocaciones de x.Equals (y) devuelven el mismo valor siempre que el objeto referenciado por xey no se modifique.

x.Equals(null) returns false.

4- Para algunos tipos de objetos, es deseable tener la prueba Equals para la igualdad de valores en lugar de la igualdad referencial. Tales implementaciones de Equals devuelven verdadero si los dos objetos tienen el mismo valor, incluso si no son la misma instancia.

Por ejemplo -

   Object obj1 = new Object();
   Object obj2 = new Object();
   Console.WriteLine(obj1.Equals(obj2));
   obj1 = obj2; 
   Console.WriteLine(obj1.Equals(obj2)); 

Salida: -

False
True

mientras se compara con -

Compara la instancia actual con otro objeto del mismo tipo y devuelve un número entero que indica si la instancia actual precede, sigue u ocurre en la misma posición en el orden de clasificación que el otro objeto.

Vuelve -

Menor que cero: esta instancia precede a obj en el orden de clasificación. Cero: esta instancia se encuentra en la misma posición en el orden de clasificación que obj. Mayor que cero: esta instancia sigue a obj en el orden de clasificación.

Puede lanzar ArgumentException si el objeto no es del mismo tipo que la instancia.

Por ejemplo, puede visitar aquí.

Así que sugiero que sea mejor usar Equals en lugar de compareTo.

Prabhat Jain
fuente
No existe ningún GetHashCode()método. ¿Te refieres hashCode()?
Marqués de Lorne
0

"igual" compara objetos y devuelve verdadero o falso y "compara con" devuelve 0 si es verdadero o un número [> 0] o [<0] si es falso aquí un ejemplo:

<!-- language: lang-java -->
//Objects Integer
Integer num1 = 1;
Integer num2 = 1;
//equal
System.out.println(num1.equals(num2));
System.out.println(num1.compareTo(num2));
//New Value
num2 = 3;//set value
//diferent
System.out.println(num1.equals(num2));
System.out.println(num1.compareTo(num2));

Resultados:

num1.equals(num2) =true
num1.compareTo(num2) =0
num1.equals(num2) =false
num1.compareTo(num2) =-1

Documentación Comparar con: https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

La documentación es igual a: https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)

David Hackro
fuente
0

Aquí una cosa es importante mientras se usa compareTo()over equals()que compareTofunciona para las clases que implementan la interfaz 'Comparable', de lo contrario arrojará un NullPointerException. StringLas clases implementan una interfaz comparable mientras StringBufferque no, por lo tanto, puede usarla "foo".compareTo("doo")en el Stringobjeto pero no en el StringBufferobjeto.

Pratik
fuente
0
String s1 = "a";
String s2 = "c";

System.out.println(s1.compareTo(s2));
System.out.println(s1.equals(s2));

Esto imprime -2 y falso

String s1 = "c";
String s2 = "a";
System.out.println(s1.compareTo(s2));
System.out.println(s1.equals(s2));

Esto imprime 2 y falso

String s1 = "c";
String s2 = "c";
System.out.println(s1.compareTo(s2));
System.out.println(s1.equals(s2));

Esto imprime 0 y verdadero

equals devuelve un valor booleano si y solo si ambas cadenas coinciden.

compareTo está destinado no solo a decir si coinciden, sino también a decir qué String es menor que el otro, y también en cuánto, lexicográficamente. Esto se usa principalmente al ordenar en colección.

Deepak Selvakumar
fuente
-1

Creo equalsy equalsIgnoreCasemétodos de Stringdevolución truey falseque es útil si desea comparar los valores del objeto de cadena, pero en el caso de implementar compareToy compareToIgnoreCasemétodos devuelve valor positivo, negativo y cero que será útil en caso de clasificación.

Prakhar Aditya
fuente