compareTo () vs égal à ()


118

Lors des tests d'égalité de String's en Java, j'ai toujours utilisé equals()parce que cela me semble être la méthode la plus naturelle. Après tout, son nom indique déjà ce qu'il est censé faire. Cependant, un de mes collègues m'a récemment dit que j'avais appris à utiliser compareTo() == 0au lieu de equals(). Cela ne me semble pas naturel (car il compareTo()est censé fournir un ordre et ne pas comparer pour l'égalité) et même quelque peu dangereux (car compareTo() == 0n'implique pas nécessairement l'égalité dans tous les cas, même si je sais que c'est le cas pour String's) pour moi.

Il ne savait pas pourquoi on lui avait appris à utiliser compareTo()au lieu de equals()for String, et je ne pouvais pas non plus trouver de raison. Est-ce vraiment une question de goût personnel ou y a-t-il une vraie raison pour l'une ou l'autre de ces méthodes?


9
Strictement parlant au niveau de la micro-optimisation, dont nous ne devrions jamais parler prématurément, .equalsIgnoreCase()est la comparaison la plus rapide si elle est appropriée, sinon .equals()c'est ce que vous voulez.

1
C'est une vieille question, mais elle contient une pépite que je voulais souligner: " compareTo() == 0n'implique pas nécessairement l'égalité dans tous les cas". C'est absolument correct! C'est exactement ce que signifie l'expression «cohérent avec égal» dans les spécifications de l'API Java, par exemple dans la spécification de la classe Comparable . Par exemple, la méthode de comparaison de String est cohérente avec equals, mais la méthode de comparaison de BigDecimal est incompatible avec equals.
Stuart marque le

Réponses:


105

Une différence est que "foo".equals((String)null)renvoie false tout en "foo".compareTo((String)null) == 0lançant une NullPointerException. Ils ne sont donc pas toujours interchangeables, même pour les cordes.


6
Je pense que vous devriez également le mentionner. equals calcule le hashcode. Le hashcode de deux chaînes différentes, bien que rare, peut être le même. Mais lors de l'utilisation de compareTo (), il vérifie les chaînes caractère par caractère. Donc, dans ce cas, deux chaînes renverront true si et seulement si leur contenu réel est égal.
Ashwin

30
Pourquoi pensez-vous que equals calcule le hashcode? Vous pouvez voir que ce n'est pas le cas: docjar.com/html/api/java/lang/String.java.html (ligne 1013).
waxwing

3
vous avez raison. Je pensais que equals et hashcode vont de pair (equals vérifie si les deux ont le même code de hachage). Alors pourquoi est-il nécessaire de remplacer ces deux méthodes si vous décidez de remplacer l'une d'entre elles.
Ashwin

3
Il est nécessaire de remplacer le hashcode lorsque nous remplaçons égal à parce que si la classe utilise des collections basées sur le hachage, y compris HashMap, HashSet et Hashtable, la classe ne fonctionnera pas correctement
varunthacker

4
@Ashwin C'est nécessaire car si .equals renvoie true, les hashcodes doivent également être égaux. Cependant, si les codes de hachage sont égaux, cela n'implique pas que .equals devrait retourner true
Alan

33

Les 2 principales différences sont les suivantes:

  1. equalsprendra n'importe quel objet comme paramètre, mais compareTone prendra que des chaînes.
  2. equalsvous indique seulement s'ils sont égaux ou non, mais compareTodonne des informations sur la manière dont les chaînes se comparent lexicographiquement.

J'ai jeté un coup d'œil au code de la classe String , et l'algorithme dans compareTo et equals est fondamentalement le même. Je crois que son opinion était juste une question de goût, et je suis d'accord avec vous - si tout ce que vous avez besoin de savoir est l'égalité des cordes et non celle qui vient en premier sur le plan lexicographique, alors j'utiliserais equals.


26

Lorsque vous comparez pour l'égalité, vous devez utiliser equals(), car il exprime votre intention de manière claire.

compareTo()présente l'inconvénient supplémentaire de ne fonctionner que sur les objets qui implémentent l' Comparableinterface.

Cela s'applique en général, pas seulement aux chaînes.


18

compareTofait plus de travail si les chaînes ont des longueurs différentes. equalspeut simplement renvoyer false, alors qu'il compareTofaut toujours examiner suffisamment de caractères pour trouver l'ordre de tri.


10

compareTo()s'applique non seulement aux chaînes mais également à tout autre objet car compareTo<T>prend un argument générique T. String est l'une des classes qui a implémenté la compareTo()méthode en implémentant l' Comparableinterface. (compareTo () est une méthode pour l'interface comparable). Ainsi, toute classe est libre d'implémenter l'interface Comparable.

Mais compareTo()donne l'ordre des objets , généralement utilisé pour trier les objets par ordre croissant ou décroissant, tout equals()en ne parlant que de l'égalité et en disant s'ils sont égaux ou non.


10

Dans un contexte de chaîne:
compareTo: compare deux chaînes de manière lexicographique.
equals: compare cette chaîne à l'objet spécifié.

compareTo compare deux chaînes par leurs caractères (au même index) et renvoie un entier (positif ou négatif) en conséquence.

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

7

equals () peut être plus efficace que compareTo () .

Une différence très importante entre compareTo et equals:

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

equals () vérifie si deux objets sont identiques ou non et renvoie un booléen.

compareTo () (à partir de l'interface Comparable) renvoie un entier. Il vérifie lequel des deux objets est "inférieur à", "égal à" ou "supérieur à" l'autre. Tous les objets ne peuvent pas être ordonnés logiquement, donc une méthode compareTo () n'a pas toujours de sens.

Notez que equals () ne définit pas l'ordre entre les objets, ce que compareTo ().

Maintenant, je vous conseille de revoir le code source des deux méthodes pour conclure que equals est préférable à compareTo qui implique des calculs mathématiques.


5

Il semble que les deux méthodes font à peu près la même chose, mais la méthode compareTo () prend un String, pas un Object, et ajoute des fonctionnalités supplémentaires en plus de la méthode normale equals (). Si vous ne vous souciez que de l'égalité, alors la méthode equals () est le meilleur choix, simplement parce que cela a plus de sens pour le prochain programmeur qui examine votre code. La différence de temps entre les deux fonctions différentes ne devrait pas avoir d'importance à moins que vous ne parcouriez une énorme quantité d'éléments. Le compareTo () est vraiment utile lorsque vous avez besoin de connaître l'ordre des chaînes dans une collection ou lorsque vous avez besoin de connaître la différence de longueur entre les chaînes qui commencent par la même séquence de caractères.

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


5

equals() devrait être la méthode de choix dans le cas du PO.

En regardant l'implémentation de equals()et compareTo()dans java.lang.String sur grepcode , nous pouvons facilement voir que equals est meilleur si nous nous préoccupons simplement de l'égalité de deux chaînes:

equals():

1012   public  boolean equals ( Object anObject) { 
1013 if ( this == anObject) {
1014 return true ;
1015 }
1016 if (anObject instanceof String ) {
1017 String anotherString = ( String ) anObject;
1018 int n = compte;
1019 if (n == anotherString.count) {
1020 car v1 [] = valeur;
1021 car v2 [] = anotherString.value;
1022 inti = décalage;
1023 int j = anotherString.offset;
1024 while (n--! = 0) {
1025 if (v1 [i ++]! = V2 [j ++])
1026 renvoie faux ;
1027 }
1028 renvoie vrai ;
1029 }
1030 }
1031 renvoie faux ;
1032 }

et compareTo():

1174   public  int compareTo ( String anotherString) { 
1175 int len1 = count;
1176 int len2 = anotherString.count;
1177 int n = Math. min (len1, len2);
1178 car v1 [] = valeur;
1179 car v2 [] = anotherString.value;
1180 int i = décalage;
1181 int j = anotherString.offset;
1183 si (i == j) {
1184 int k = i;
1185 int lim = n + i;
1186 tandis que (k <lim) {
1187 car c1 = v1 [k];
1188 car c2 = v2 [k];
1189 si (c1! = C2) {
1190 renvoie c1 - c2;
1191 }
1192 k ++;
1193 }
1194 } else {
1195 while (n--! = 0) {
1196 car c1 = v1 [i ++];
1197 car c2 = v2 [j ++];
1198 si (c1! = C2) {
1199 renvoie c1 - c2;
1200 }
1201 }
1202 }
1203 retour len1 - len2;
1204 }

Lorsque l'une des chaînes est le préfixe d'une autre, les performances de compareTo()sont pires car il doit encore déterminer l'ordre lexicographique tout equals()en ne s'inquiétant plus et retournant false immédiatement.

À mon avis, nous devrions utiliser ces deux comme prévu:

  • equals() pour vérifier l'égalité, et
  • compareTo() pour trouver l'ordre lexical.

3

equals () vérifie si deux chaînes sont égales ou non. Il donne une valeur booléenne. compareTo () vérifie si l'objet string est égal, supérieur ou inférieur à l'autre objet string.Il donne le résultat comme suit: 1 si l'objet string est supérieur 0 si les deux sont égaux -1 si la chaîne est plus petite que l'autre chaîne

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


2

Ceci est une expérience de nécromancie :-)

La plupart des réponses comparent les performances et les différences d'API. Ils manquent le point fondamental que les deux opérations ont simplement une sémantique différente.

Votre intuition est correcte. x.equals (y) n'est pas interchangeable avec x.compareTo (y) == 0. Le premier compare l'identité, tandis que l'autre compare la notion de «taille». Il est vrai que dans de nombreux cas, en particulier avec les types primitifs, ces deux co-alignent.

Le cas général est le suivant:

Si x et y sont identiques, ils partagent la même 'taille': si x.equals (y) est vrai => x.compareTo (y) vaut 0.

Cependant, si x et y partagent la même taille, cela ne signifie pas qu'ils sont identiques.

si x.compareTo (y) vaut 0 ne signifie pas nécessairement que x.equals (y) est vrai.

Un exemple convaincant où l'identité diffère de la taille serait les nombres complexes. Supposons que la comparaison soit faite par leur valeur absolue. Donc, étant donné deux nombres complexes: Z1 = a1 + b1 * i et Z2 = a2 + b2 * i:

Z1.equals (z2) renvoie vrai si et seulement si a1 = a2 et b1 = b2.

Cependant, Z1.compareTo (Z2) renvoie 0 pour et un nombre infini de paires (a1, b1) et (a2, b2) tant qu'elles satisfont à la condition a1 ^ 2 + b1 ^ 2 == a2 ^ 2 + b2 ^ 2.


1
x.equals (y) ne signifie pas identité, cela signifie égalité. L'identité est comparée à l'aide de x == y pour les types définis par l'utilisateur en Java.
Fernando Pelliccioni

2

Equals peut être plus efficace que compareTo.

Si la longueur des séquences de caractères dans String ne correspond pas, il n'y a aucun moyen que les chaînes soient égales, donc le rejet peut être beaucoup plus rapide.

De plus s'il s'agit du même objet (égalité d'identité plutôt qu'égalité logique), il sera également plus efficace.

S'ils implémentaient également la mise en cache de hashCode, il pourrait être encore plus rapide de rejeter les non-égaux au cas où leur hashCode ne correspond pas.


2

String.equals()nécessite l'invocation d'un instanceofopérateur alors compareTo()que ne l'exige pas. Mon collègue a noté une grande baisse des performances causée par un nombre excessif d' instanceofappels dans la equals()méthode, mais mon test s'est avéré compareTo()être légèrement plus rapide.

J'utilisais cependant Java 1.6. Sur d'autres versions (ou d'autres fournisseurs de JDK), la différence pourrait être plus importante.

Le test a comparé chaque chaîne à chaque chaîne dans 1000 tableaux d'éléments, répétés 10 fois.


1
Je suppose que vous devez avoir utilisé des chaînes très courtes, toutes de même longueur et avec une grande diversité au premier caractère pour obtenir un résultat où compareTo()est plus rapide que equals()? Mais pour la plupart des ensembles de données du monde réel, equals()c'est beaucoup plus rapide que compareTo() == 0. equals()brille si les chaînes ont un préfixe commun mais des longueurs différentes ou si elles sont en fait le même objet.
x4u

Eh bien, mon test était contre l'hypotesis que instanceof est un tueur de performances, donc les cordes étaient vraiment courtes.
Danubian Sailor

Si votre chaîne est aléatoire et diffère principalement en longueur, le choix le plus évident devrait être la méthode equals () sur compareTo () car dans la plupart des cas, elle retournera immédiatement false si elles ne sont pas égales en longueur.
sactiw

1
  1. equalspeut prendre n'importe quel objet comme paramètre mais compareTone peut accepter que String.

  2. quand cometo null, compareTolancera une exception

  3. lorsque vous voulez savoir où se produisent les différences, vous pouvez utiliser compareTo.


compareTo peut prendre n'importe quel objet comme argument. Comme @apurva jadhav l'a dit ci-dessus, comparable prend un argument générique. Si vous implémentez comaparable en tant que Comparable <String>, vous êtes autorisé à utiliser uniquement des chaînes.
Gaurav Kumar

1
  • equals: requis pour vérifier l'égalité et limiter les doublons. De nombreuses classes de la bibliothèque Java l'utilisent au cas où elles voudraient trouver des doublons. par exemple HashSet.add(ob1), ajoutera seulement si cela n'existe pas. Donc, si vous étendez certaines classes comme celle-ci, remplacez equals().

  • compareTo: requis pour la commande d'élément. Encore une fois pour un tri stable, vous avez besoin de l'égalité, il y a donc un retour 0.


0

Équivaut à -

1- Remplacez la méthode GetHashCode pour permettre à un type de fonctionner correctement dans une table de hachage.

2- Ne lancez pas d'exception dans l'implémentation d'une méthode Equals. Au lieu de cela, retournez false pour un argument nul.

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.

Les appels successifs de x.Equals (y) renvoient la même valeur tant que l'objet référencé par x et y n'est pas modifié.

x.Equals(null) returns false.

4- Pour certains types d'objets, il est souhaitable que Equals teste l'égalité des valeurs au lieu de l'égalité référentielle. De telles implémentations d'Equals renvoient true si les deux objets ont la même valeur, même s'ils ne sont pas la même instance.

Par exemple -

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

Production :-

False
True

tandis que compareTo -

Compare l'instance actuelle avec un autre objet du même type et renvoie un entier qui indique si l'instance actuelle précède, suit ou se produit à la même position dans l'ordre de tri que l'autre objet.

Il renvoie -

Inférieur à zéro - Cette instance précède obj dans l'ordre de tri. Zéro - Cette instance se produit dans la même position dans l'ordre de tri que obj. Supérieur à zéro - Cette instance suit obj dans l'ordre de tri.

Il peut lever ArgumentException si l'objet n'est pas du même type que l'instance.

Par exemple, vous pouvez visiter ici.

Je suggère donc de mieux utiliser Equals au lieu de compareTo.


Il n'y a pas de GetHashCode()méthode. Voulez-vous dire hashCode()?
Marquis of Lorne

0

"equals" compare des objets et renvoie vrai ou faux et "compare to" renvoie 0 si est vrai ou un nombre [> 0] ou [<0] si est faux, voici un exemple:

<!-- 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));

Résultats:

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

Documentation Comparer avec: https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

Documentation égale: https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)


0

Ici, une chose est importante lors de l'utilisation de compareTo()over equals()qui compareTofonctionne pour les classes qui implémentent l'interface 'Comparable' sinon cela lancera un NullPointerException. Stringclasses implémente l'interface comparable alors que ce StringBuffern'est pas le cas, vous pouvez donc l'utiliser "foo".compareTo("doo")dans Stringobject mais pas dans StringBufferObject.


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

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

Cela imprime -2 et faux

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

Cela imprime 2 et faux

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

Cela imprime 0 et vrai

equals renvoie un booléen si et seulement si les deux chaînes correspondent.

compareTo est destiné non seulement à dire s'ils correspondent, mais aussi à dire quelle String est inférieure à l'autre, et aussi de combien, d'un point de vue lexicographique. Ceci est principalement utilisé lors du tri dans la collection.


-1

Je crois equalset equalsIgnoreCaseméthodes de Stringretour trueet falsequi est utile si vous vouliez comparer les valeurs de l'objet string, mais en cas de mise en œuvre compareToet de compareToIgnoreCaseméthodes renvoie une valeur positive, négative et nulle qui sera utile en cas de tri.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.