compareTo () vs. equals ()


118

Beim Testen auf Gleichheit Stringin Java habe ich immer verwendet, equals()weil dies für mich die natürlichste Methode dafür zu sein scheint. Immerhin sagt der Name schon, was er tun soll. Ein Kollege von mir sagte mir jedoch kürzlich, man habe mir beigebracht, compareTo() == 0statt zu benutzen equals(). Dies fühlt sich für mich unnatürlich an (da compareTo()dies eine Ordnung bieten und nicht für Gleichheit vergleichen soll) und sogar etwas gefährlich (weil compareTo() == 0dies nicht unbedingt in allen Fällen Gleichheit impliziert, obwohl ich weiß, dass dies für Stringmich der Fall ist ).

Er wusste nicht, warum ihm beigebracht wurde, compareTo()statt equals()für zu verwenden String, und ich konnte auch keinen Grund finden, warum. Ist das wirklich eine Frage des persönlichen Geschmacks oder gibt es einen wirklichen Grund für eine der beiden Methoden?


9
Streng genommen ist eine Mikrooptimierungsebene, auf der wir niemals vorzeitig sprechen sollten, .equalsIgnoreCase()der schnellste Vergleich, wenn dies angemessen ist, andernfalls .equals()ist es das, was Sie wollen.

1
Dies ist eine alte Frage, aber sie enthält ein Nugget, das ich hervorheben wollte: " compareTo() == 0Bedeutet nicht unbedingt in allen Fällen Gleichheit". Das ist absolut richtig! Dies ist genau das, was der Ausdruck "konsistent mit Gleichen" in den Java-API-Spezifikationen bedeutet, beispielsweise in der Vergleichsspezifikation . Zum Beispiel ist String der Vergleichsmethode mit equals konsistent, aber BigDecimal der Vergleichsmethode ist inkonsistent mit equals.
Stuart Marks

Antworten:


104

Ein Unterschied besteht darin, dass "foo".equals((String)null)false zurückgegeben wird, während "foo".compareTo((String)null) == 0eine NullPointerException ausgelöst wird. Sie sind also auch für Strings nicht immer austauschbar.


6
Ich denke, Sie sollten dies auch erwähnen. gleich berechnet den Hashcode. Der Hashcode von zwei verschiedenen Zeichenfolgen ist zwar selten, kann jedoch identisch sein. Bei Verwendung von compareTo () werden die Zeichenfolgen jedoch zeichenweise überprüft. In diesem Fall geben zwei Zeichenfolgen nur dann true zurück, wenn ihr tatsächlicher Inhalt gleich ist.
Ashwin

30
Warum wird der Hashcode Ihrer Meinung nach gleich berechnet? Sie können sehen, dass dies nicht der Fall ist: docjar.com/html/api/java/lang/String.java.html (Zeile 1013).
Waxwing

3
Du hast recht. Ich dachte, dass gleich und Hashcode Hand in Hand gehen (gleich prüft, ob beide den gleichen Hashcode haben). Warum müssen dann beide Methoden überschrieben werden, wenn Sie eine dieser Methoden überschreiben möchten?
Ashwin

3
Es ist notwendig, Hashcode zu überschreiben, wenn wir gleich überschreiben, denn wenn die Klasse Hash-basierte Sammlungen verwendet, einschließlich HashMap, HashSet und Hashtable, funktioniert die Klasse nicht richtig
varunthacker

4
@Ashwin Dies ist erforderlich, da die Hashcodes auch gleich sein sollten, wenn .equals true zurückgibt. Wenn jedoch die Hashcodes gleich sind, bedeutet dies nicht, dass .equals true zurückgeben sollten
Alan,

33

Die 2 Hauptunterschiede sind:

  1. equalsnimmt jedes Objekt als Parameter, aber compareTonur Strings.
  2. equalssagt Ihnen nur, ob sie gleich sind oder nicht, compareTogibt aber Auskunft darüber, wie die Strings lexikographisch verglichen werden.

Ich habe mir den String-Klassencode angesehen , und der Algorithmus in compareTo und equals sieht im Grunde gleich aus. Ich glaube, seine Meinung war nur eine Frage des Geschmacks, und ich stimme Ihnen zu - wenn Sie nur die Gleichheit der Saiten wissen müssen und nicht, welche lexikographisch zuerst kommt, dann würde ich sie verwenden equals.


26

Wenn Sie für Gleichheit vergleichen, sollten Sie verwenden equals(), weil es Ihre Absicht in klarer Weise ausdrückt.

compareTo() hat den zusätzlichen Nachteil, dass es nur bei Objekten funktioniert, die das implementieren Comparable Schnittstelle .

Dies gilt im Allgemeinen nicht nur für Strings.


18

compareTohat mehr Arbeit gemacht, wenn die Saiten unterschiedlich lang sind. equalskann einfach false zurückgeben, compareTomuss aber immer genügend Zeichen untersuchen, um die Sortierreihenfolge zu finden.


10

compareTo()Dies gilt nicht nur für Strings, sondern auch für jedes andere Objekt, da compareTo<T>ein generisches Argument verwendet wird T. String ist eine der Klassen, die die compareTo()Methode durch Implementierung der ComparableSchnittstelle implementiert haben. (compareTo () ist eine Methode für die vergleichbare Schnittstelle). Es steht also jeder Klasse frei, die Schnittstelle Comparable zu implementieren.

Aber compareTo()gibt die Reihenfolge der Objekte , typischerweise verwendet in Objekte in aufsteigender Sortierung oder absteigender Reihenfolge , während equals()nur über die Gleichheit reden und sagen , ob sie gleich sind oder nicht.


10

Im
Zeichenfolgenkontext: compareTo: Vergleicht zwei Zeichenfolgen lexikografisch.
gleich: Vergleicht diese Zeichenfolge mit dem angegebenen Objekt.

compareTo vergleicht zwei Zeichenfolgen anhand ihrer Zeichen (am selben Index) und gibt entsprechend eine Ganzzahl (positiv oder negativ) zurück.

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 () kann effizienter sein als compareTo () .

Ein sehr wichtiger Unterschied zwischen compareTo und equals:

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

equals () prüft, ob zwei Objekte gleich sind oder nicht und gibt einen Booleschen Wert zurück.

compareTo () (von der Schnittstelle Comparable ) gibt eine Ganzzahl zurück. Es wird geprüft, welches der beiden Objekte "kleiner als", "gleich" oder "größer als" das andere ist. Nicht alle Objekte können logisch geordnet werden, daher ist eine compareTo () -Methode nicht immer sinnvoll.

Beachten Sie, dass equals () nicht die Reihenfolge zwischen Objekten definiert, wie es compareTo () tut.

Jetzt rate ich Ihnen, den Quellcode beider Methoden zu überprüfen, um zu dem Schluss zu kommen, dass Gleichheit gegenüber compareTo vorzuziehen ist, das einige mathematische Berechnungen umfasst.


5

Es scheint, dass beide Methoden so ziemlich dasselbe tun, aber die compareTo () -Methode nimmt einen String und kein Objekt auf und fügt zusätzlich zur normalen equals () -Methode einige zusätzliche Funktionen hinzu. Wenn Sie sich nur für Gleichheit interessieren, ist die Methode equals () die beste Wahl, einfach weil sie für den nächsten Programmierer, der sich Ihren Code ansieht, sinnvoller ist. Der Zeitunterschied zwischen den beiden verschiedenen Funktionen sollte keine Rolle spielen, es sei denn, Sie durchlaufen eine große Anzahl von Elementen. Das compareTo () ist sehr nützlich, wenn Sie die Reihenfolge der Zeichenfolgen in einer Sammlung kennen müssen oder wenn Sie den Längenunterschied zwischen Zeichenfolgen kennen müssen, die mit derselben Zeichenfolge beginnen.

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


5

equals() sollte im Fall des OP die Methode der Wahl sein.

Wenn wir uns die Implementierung von equals()und compareTo()in java.lang.String auf grepcode ansehen , können wir leicht erkennen, dass Gleichheit besser ist, wenn wir uns nur mit der Gleichheit zweier Zeichenfolgen befassen:

equals()::

1012   public  boolean equals ( Object anObject) { 
1013 if ( this == anObject) {
1014 return true ;
1015 }
1016 if (anObject- Instanz von String ) {
1017 String anotherString = ( String ) anObject;
1018 int n = count;
1019 if (n == anotherString.count) {
1020 char v1 [] = value;
1021 char v2 [] = anotherString.value;
1022 inti = Versatz;
1023 int j = anotherString.offset;
1024 while (n--! = 0) {
1025 if (v1 [i ++]! = V2 [j ++])
1026 return false ;
1027 }
1028 return true ;
1029 }
1030 }
1031 return false ;
1032 }

und compareTo():

1174   public  int compareTo ( String anotherString) { 
1175 int len1 = count;
1176 int len2 = anotherString.count;
1177 int n = Math. min (len1, len2); 1178 char v1 [] = Wert; 1179 char v2 [] = anotherString.value; 1180 int i = Offset; 1181 int j = anotherString.offset; 1183 if (i == j) { 1184 int k = i; 1185 int lim = n + i; 1186 while (k <lim) { c1 = v1 [k]; 1188 char c2 = v2 [k]; 1189 if (c1! = C2) { 1190 return c1 - c2; 1191 } 1192 k ++; 1193 }








1187 1194 } else { 1195 while (n--! = 0) { 1196 char c1 = v1 [i ++]; 1197 char c2 = v2 [j ++]; 1198 if (c1! = C2) { 1199 return c1 - c2; 1200 } 1201 } 1202 } 1203 char















returnlen1 - len2;
1204 }

Wenn eine der Zeichenfolgen ein Präfix einer anderen ist, ist die Leistung von compareTo()schlechter, da die lexikografische Reihenfolge noch bestimmt equals()werden muss, ohne sich mehr Sorgen zu machen und sofort false zurückzugeben.

Meiner Meinung nach sollten wir diese beiden so verwenden, wie sie beabsichtigt waren:

  • equals() auf Gleichheit prüfen und
  • compareTo() um die lexikalische Reihenfolge zu finden.

3

equals () prüft, ob zwei Zeichenfolgen gleich sind oder nicht. Es gibt einen booleschen Wert. compareTo () prüft, ob das Zeichenfolgenobjekt dem anderen Zeichenfolgenobjekt entspricht, größer oder kleiner ist. Das Ergebnis lautet: 1, wenn das Zeichenfolgenobjekt größer ist 0, wenn beide gleich -1 sind, wenn die Zeichenfolge kleiner als die andere Zeichenfolge ist

Gl.:

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

Dies ist ein Experiment in Nekromantie :-)

Die meisten Antworten vergleichen Leistungs- und API-Unterschiede. Sie übersehen den grundlegenden Punkt, dass die beiden Operationen einfach unterschiedliche Semantik haben.

Ihre Intuition ist richtig. x.equals (y) ist nicht austauschbar mit x.compareTo (y) == 0. Der erste vergleicht die Identität, während der andere den Begriff 'Größe' vergleicht. Es ist wahr, dass in vielen Fällen, insbesondere bei primitiven Typen, diese beiden zusammenpassen.

Der allgemeine Fall ist folgender:

Wenn x und y identisch sind, haben sie dieselbe 'Größe': Wenn x.equals (y) wahr ist => x.compareTo (y) ist 0.

Wenn jedoch x und y dieselbe Größe haben, bedeutet dies nicht, dass sie identisch sind.

Wenn x.compareTo (y) 0 ist, bedeutet dies nicht unbedingt, dass x.equals (y) wahr ist.

Ein überzeugendes Beispiel, bei dem sich Identität von Größe unterscheidet, wären komplexe Zahlen. Angenommen, der Vergleich erfolgt nach ihrem absoluten Wert. Also zwei komplexe Zahlen gegeben: Z1 = a1 + b1 * i und Z2 = a2 + b2 * i:

Z1.equals (z2) gibt genau dann true zurück, wenn a1 = a2 und b1 = b2.

Z1.compareTo (Z2) gibt jedoch 0 für und eine unendliche Anzahl von (a1, b1) und (a2, b2) Paaren zurück, solange sie die Bedingung a1 ^ 2 + b1 ^ 2 == a2 ^ 2 + b2 ^ 2 erfüllen.


1
x.equals (y) bedeutet nicht Identität, sondern Gleichheit. Die Identität wird mit x == y für benutzerdefinierte Typen in Java verglichen.
Fernando Pelliccioni

2

Gleiche können effizienter sein als compareTo.

Wenn die Länge der Zeichenfolgen in String nicht übereinstimmt, sind die Strings auf keinen Fall gleich, sodass die Zurückweisung viel schneller erfolgen kann.

Wenn es sich um dasselbe Objekt handelt (Identitätsgleichheit statt logische Gleichheit), ist es außerdem effizienter.

Wenn sie auch das HashCode-Caching implementiert haben, könnte es noch schneller sein, Ungleichwerte abzulehnen, falls ihre HashCodes nicht übereinstimmen.


2

String.equals()erfordert das Aufrufen des instanceofOperators, während dies compareTo()nicht erforderlich ist. Mein Kollege hat einen großen Leistungsabfall festgestellt, der durch eine übermäßige Anzahl von instanceofAufrufen in der equals()Methode verursacht wurde. Mein Test hat sich jedoch bewährtcompareTo() nur etwas schneller sein.

Ich habe jedoch Java 1.6 verwendet. Bei anderen Versionen (oder anderen JDK-Anbietern) kann der Unterschied größer sein.

Der Test verglich jede Zeichenfolge in 1000 Elementarrays, die zehnmal wiederholt wurden.


1
Ich denke, Sie müssen sehr kurze Saiten verwendet haben, alle gleich lang und mit großer Vielfalt beim ersten Zeichen, um ein Ergebnis zu erzielen, bei dem compareTo()es schneller ist als equals()? Für die meisten Datensätze in der realen Welt equals()ist dies jedoch viel schneller als compareTo() == 0. equals()leuchtet, wenn die Zeichenfolgen ein gemeinsames Präfix, aber unterschiedliche Längen haben oder wenn sie tatsächlich dasselbe Objekt sind.
x4u

Nun, mein Test war gegen die Hypotese, dass Instanz ein Performance-Killer ist, also waren die Saiten in der Tat kurz.
Danubian Sailor

Wenn Ihre Zeichenfolge zufällig ist und sich größtenteils in der Länge unterscheidet, sollte die Methode equals () gegenüber compareTo () offensichtlicher sein, da in den meisten Fällen sofort false zurückgegeben wird, wenn sie nicht gleich lang sind.
Sactiw

1
  1. equalskann jedes Objekt als Parameter nehmen, aber compareTonur String.

  2. Wenn cometo null, compareTowird eine Ausnahme ausgelöst

  3. Wenn Sie wissen möchten, wo der Unterschied auftritt, können Sie verwenden compareTo.


compareTo kann jedes Objekt als Argument verwenden. Wie @apurva jadhav oben sagte, nimmt vergleichbar ein generisches Argument. Wenn Sie comaparable als Comparable <String> implementieren, dürfen Sie nur Zeichenfolgen verwenden.
Gaurav Kumar

1
  • equals: Erforderlich für die Überprüfung der Gleichheit und die Einschränkung von Duplikaten. Viele Klassen der Java-Bibliothek verwenden dies, wenn sie Duplikate suchen möchten. zB HashSet.add(ob1)wird nur hinzugefügt, wenn das nicht existiert. Wenn Sie also einige Klassen wie diese erweitern, überschreiben Sie sie equals().

  • compareTo: Erforderlich für die Bestellung des Elements. Auch hier benötigen Sie für eine stabile Sortierung Gleichheit, daher gibt es eine Rückgabe 0.


0

Gleich -

1- Überschreiben Sie die GetHashCode-Methode, damit ein Typ in einer Hash-Tabelle ordnungsgemäß funktioniert.

2- Bei der Implementierung einer Equals-Methode keine Ausnahme auslösen. Geben Sie stattdessen false für ein Nullargument zurück.

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.

Aufeinanderfolgende Aufrufe von x.Equals (y) geben denselben Wert zurück, solange das von x und y referenzierte Objekt nicht geändert wird.

x.Equals(null) returns false.

4- Für einige Arten von Objekten ist es wünschenswert, dass Equals anstelle von referentieller Gleichheit auf Wertgleichheit getestet wird. Solche Implementierungen von Equals geben true zurück, wenn die beiden Objekte denselben Wert haben, auch wenn sie nicht dieselbe Instanz sind.

Zum Beispiel -

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

Ausgabe :-

False
True

während compareTo -

Vergleicht die aktuelle Instanz mit einem anderen Objekt desselben Typs und gibt eine Ganzzahl zurück, die angibt, ob die aktuelle Instanz in der Sortierreihenfolge dem anderen Objekt vorausgeht, folgt oder an derselben Position auftritt.

Es kehrt zurück -

Kleiner als Null - Diese Instanz steht in der Sortierreihenfolge vor obj. Null - Diese Instanz tritt an derselben Position in der Sortierreihenfolge wie obj auf. Größer als Null - Diese Instanz folgt obj in der Sortierreihenfolge.

Es kann eine ArgumentException auslösen, wenn das Objekt nicht vom Typ der Instanz ist.

Zum Beispiel können Sie hier besuchen.

Daher empfehle ich besser, Equals anstelle von compareTo zu verwenden.


Es gibt keine GetHashCode()Methode. Meinst du hashCode()?
Marquis von Lorne

0

"gleich" vergleicht Objekte und gibt true oder false zurück und "compare to" gibt 0 zurück, wenn true oder eine Zahl [> 0] oder [<0], wenn dies hier falsch ist. Ein Beispiel:

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

Ergebnisse:

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

Dokumentation Vergleichen Sie mit: https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

Dokumentation gleich: https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)


0

Hier ist eine Sache wichtig, während compareTo()over verwendet wird equals(), compareTodie für die Klassen funktioniert, die die 'Comparable'-Schnittstelle implementieren, andernfalls wird a ausgelöst NullPointerException. StringKlassen implementiert eine vergleichbare Schnittstelle, die Sie StringBufferjedoch nicht "foo".compareTo("doo")in StringObjekt, aber nicht in StringBufferObjekt verwenden können.


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

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

Dies gibt -2 und false aus

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

Dies gibt 2 und false aus

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

Dies gibt 0 und true aus

equals gibt genau dann einen booleschen Wert zurück, wenn beide Zeichenfolgen übereinstimmen.

compareTo soll nicht nur sagen, ob sie übereinstimmen, sondern auch, welcher String kleiner als der andere ist und auch wie viel lexikographisch. Dies wird hauptsächlich beim Sortieren in der Sammlung verwendet.


-1

Ich glaube equalsund equalsIgnoreCaseMethoden der StringRückgabe trueund falsedas ist nützlich, wenn Sie die Werte des String-Objekts vergleichen wollten, aber im Falle der Implementierung compareTound compareToIgnoreCaseMethoden gibt positive, negative und Null-Wert, die im Fall der Sortierung nützlich sein wird.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.