compareTo () vs. uguale ()


118

Quando Stringho testato l'uguaglianza di s in Java, l'ho sempre usato equals()perché a me questo sembra essere il metodo più naturale per farlo. Dopotutto, il suo nome dice già cosa intende fare. Tuttavia, un mio collega recentemente mi ha detto che mi è stato insegnato a usare compareTo() == 0invece di equals(). Questo mi sembra innaturale (poiché ha lo compareTo()scopo di fornire un ordine e non confrontare per l'uguaglianza) e anche un po 'pericoloso (perché compareTo() == 0non implica necessariamente l'uguaglianza in tutti i casi, anche se so che lo fa per String' s) per me.

Non sapeva perché gli fosse stato insegnato a usare al compareTo()posto di equals()for String, e non riuscivo a trovarne alcuna ragione. È davvero una questione di gusto personale o c'è una vera ragione per entrambi i metodi?


9
A rigor di termini a livello di microottimizzazione, di cui non dovremmo mai parlare prematuramente, .equalsIgnoreCase()è il confronto più veloce se è appropriato, altrimenti .equals()è quello che vuoi.

1
Questa è una vecchia domanda, ma contiene una pepita che volevo sottolineare: " compareTo() == 0non implica necessariamente l'uguaglianza in tutti i casi". Questo è assolutamente corretto! Questo è esattamente il significato della frase "coerente con uguale" nelle specifiche dell'API Java, ad esempio nella specifica della classe Comparable . Ad esempio, il metodo di confronto di String è coerente con uguale, ma il metodo di confronto di BigDecimal non è coerente con uguale.
Stuart Marks,

Risposte:


104

Una differenza è che "foo".equals((String)null)restituisce false mentre "foo".compareTo((String)null) == 0genera un'eccezione NullPointerException. Quindi non sono sempre intercambiabili anche per gli archi.


6
Penso che dovresti menzionare anche questo. equals calcola il codice hash. Il codice hash di due stringhe diverse, sebbene raro, può essere lo stesso. Ma quando si usa compareTo (), controlla le stringhe carattere per carattere. Quindi in questo caso due stringhe restituiranno true se e solo se il loro contenuto effettivo è uguale.
Ashwin

30
Perché pensi che equivale a calcolare l'hashcode? Puoi vedere che non è così: docjar.com/html/api/java/lang/String.java.html (riga 1013).
waxwing

3
hai ragione. Ho pensato che uguale e hashcode vadano di pari passo (uguale controlla se entrambi hanno lo stesso codice hash). Allora perché è necessario sovrascrivere entrambi questi metodi se si decide di sovrascrivere uno qualsiasi di essi.
Ashwin

3
È necessario sovrascrivere hashcode quando sovrascriviamo uguale a perché se la classe utilizza raccolte basate su hash, inclusi HashMap, HashSet e Hashtable, la classe non funzionerà correttamente
varunthacker

4
@Ashwin È necessario perché se .equals restituisce true, anche i codici hash dovrebbero essere uguali. Tuttavia, se i codici hash sono uguali, non implica che .equals debba restituire true
Alan

33

Le 2 differenze principali sono che:

  1. equalsprenderà qualsiasi oggetto come parametro, ma compareToaccetterà solo stringhe.
  2. equalsti dice solo se sono uguali o meno, ma compareTofornisce informazioni su come le stringhe si confrontano lessicograficamente.

Ho dato un'occhiata al codice della classe String e l'algoritmo all'interno di compareTo ed equals sembra fondamentalmente lo stesso. Credo che la sua opinione fosse solo una questione di gusti, e sono d'accordo con te - se tutto ciò che devi sapere è l'uguaglianza delle corde e non quale viene prima lessicograficamente, allora la userei equals.


26

Quando confronti per l'uguaglianza dovresti usare equals(), perché esprime il tuo intento in modo chiaro.

compareTo()ha l'ulteriore svantaggio di funzionare solo su oggetti che implementano l' Comparableinterfaccia.

Questo vale in generale, non solo per gli archi.


18

compareTodeve fare più lavoro se le corde hanno lunghezze diverse. equalspuò semplicemente restituire false, mentre compareTodeve sempre esaminare un numero sufficiente di caratteri per trovare l'ordinamento.


10

compareTo()non si applica solo alle stringhe ma anche a qualsiasi altro oggetto perché compareTo<T>accetta un argomento generico T. String è una delle classi che ha implementato il compareTo()metodo implementando l' Comparableinterfaccia. (compareTo () è un metodo per l'interfaccia comparabile). Quindi qualsiasi classe è libera di implementare l'interfaccia Comparable.

Ma compareTo()fornisce l'ordinamento degli oggetti , utilizzato tipicamente per ordinare gli oggetti in ordine crescente o decrescente mentre equals()parlerà solo dell'uguaglianza e dirà se sono uguali o meno.


10

In String Context:
compareTo: confronta lessicograficamente due stringhe.
è uguale a: confronta questa stringa con l'oggetto specificato.

compareTo confronta due stringhe in base ai loro caratteri (allo stesso indice) e restituisce un numero intero (positivo o negativo) di conseguenza.

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 () può essere più efficiente di compareTo () .

Una differenza molto importante tra compareTo e uguale:

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

equals () controlla se due oggetti sono uguali o meno e restituisce un valore booleano.

compareTo () (dall'interfaccia Comparable) restituisce un numero intero. Controlla quale dei due oggetti è "minore di", "uguale a" o "maggiore di" l'altro. Non tutti gli oggetti possono essere ordinati logicamente, quindi un metodo compareTo () non ha sempre senso.

Nota che equals () non definisce l'ordinamento tra gli oggetti, come fa compareTo ().

Ora ti consiglio di rivedere il codice sorgente di entrambi i metodi per concludere che è preferibile uguale a compareTo che coinvolge alcuni calcoli matematici.


5

Sembra che entrambi i metodi facciano praticamente la stessa cosa, ma il metodo compareTo () accetta una stringa, non un oggetto, e aggiunge alcune funzionalità extra oltre al normale metodo equals (). Se tutto ciò che ti interessa è l'uguaglianza, allora il metodo equals () è la scelta migliore, semplicemente perché ha più senso per il prossimo programmatore che dà un'occhiata al tuo codice. La differenza di tempo tra le due diverse funzioni non dovrebbe avere importanza a meno che tu non stia eseguendo un ciclo su una quantità enorme di elementi. Il compareTo () è davvero utile quando è necessario conoscere l'ordine delle stringhe in una raccolta o quando è necessario conoscere la differenza di lunghezza tra stringhe che iniziano con la stessa sequenza di caratteri.

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


5

equals() dovrebbe essere il metodo di scelta nel caso del PO.

Guardando l'implementazione di equals()e compareTo()in java.lang.String su grepcode , possiamo facilmente vedere che è meglio uguale se ci interessa solo l'uguaglianza di due stringhe:

equals():

1012   public  boolean è uguale a ( Object anObject) { 
1013 if ( this == anObject) {
1014 return true ;
1015 }
1016 if (anObject instanceof 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 = offset;
1023 int j = anotherString.offset;
1024 while (n--! = 0) {
1025 if (v1 [i ++]! = V2 [j ++])
1026 restituisce false ;
1027 }
1028 restituisce true ;
1029 }
1030 }
1031 return false ;
1032 }

e 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 [] = value;
1179 char v2 [] = anotherString.value;
1180 int i = offset;
1181 int j = anotherString.offset;
1183 se (i == j) {
1184 int k = i;
1185 int lim = n + i;
1186 while (k <lim) {
1187 char c1 = v1 [k];
1188 char c2 = v2 [k];
1189 se (c1! = C2) {
1190 restituisce c1 - c2;
1191 }
1192 k ++;
1193 }
1194 } else {
1195 while (n--! = 0) {
1196 char c1 = v1 [i ++];
1197 char c2 = v2 [j ++];
1198 se (c1! = C2) {
1199 restituisce c1 - c2;
1200 }
1201 }
1202 }
1203 return len1 - len2;
1204 }

Quando una delle stringhe è prefisso di un'altra, la prestazione di compareTo()è peggiore in quanto deve ancora determinare l'ordinamento lessicografico mentre equals()non si preoccupa più e restituisce immediatamente false.

A mio parere, dovremmo usare questi due come erano intesi:

  • equals() per verificare l'uguaglianza e
  • compareTo() per trovare l'ordinamento lessicale.

3

equals () controlla se due stringhe sono uguali o meno e fornisce un valore booleano. compareTo () controlla se l'oggetto stringa è uguale, maggiore o minore dell'altro oggetto stringa. Restituisce il risultato come: 1 se oggetto stringa è maggiore 0 se entrambi sono uguali -1 se stringa è minore dell'altra stringa

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

Questo è un esperimento di negromanzia :-)

La maggior parte delle risposte confronta prestazioni e differenze API. Mancano il punto fondamentale che le due operazioni hanno semplicemente una semantica diversa.

La tua intuizione è corretta. x.equals (y) non è intercambiabile con x.compareTo (y) == 0. Il primo confronta l'identità, mentre l'altro confronta la nozione di "dimensione". È vero che in molti casi, specialmente con i tipi primitivi, questi due si allineano.

Il caso generale è questo:

Se x e y sono identici, condividono la stessa 'dimensione': se x.equals (y) è vero => x.compareTo (y) è 0.

Tuttavia, se x e y condividono la stessa dimensione, non significa che siano identici.

se x.compareTo (y) è 0 non significa necessariamente che x.equals (y) è vero.

Un esempio convincente in cui l'identità differisce dalla dimensione sarebbero i numeri complessi. Supponiamo che il confronto venga effettuato in base al loro valore assoluto. Quindi dati due numeri complessi: Z1 = a1 + b1 * i e Z2 = a2 + b2 * i:

Z1.equals (z2) restituisce vero se e solo se a1 = a2 e b1 = b2.

Tuttavia Z1.compareTo (Z2) restituisce 0 per e un numero infinito di coppie (a1, b1) e (a2, b2) purché soddisfino la condizione a1 ^ 2 + b1 ^ 2 == a2 ^ 2 + b2 ^ 2.


1
x.equals (y) non significa identità, significa uguaglianza. L'identità viene confrontata utilizzando x == y per i tipi definiti dall'utente in Java.
Fernando Pelliccioni

2

Equals può essere più efficiente di compareTo.

Se la lunghezza delle sequenze di caratteri in String non corrisponde, non è possibile che le stringhe siano uguali, quindi il rifiuto può essere molto più veloce.

Inoltre, se è lo stesso oggetto (uguaglianza di identità piuttosto che uguaglianza logica), sarà anche più efficiente.

Se implementassero anche il caching hashCode, potrebbe essere ancora più veloce rifiutare i non uguali nel caso in cui il loro hashCode non corrisponda.


2

String.equals()richiede l'invocazione di un instanceofoperatore mentre compareTo()non lo richiede. Il mio collega ha notato un notevole calo delle prestazioni causato da un numero eccessivo di instanceofchiamate nel equals()metodo, tuttavia il mio test si è rivelato compareTo()solo leggermente più veloce.

Tuttavia, stavo usando Java 1.6. Su altre versioni (o altri fornitori di JDK) la differenza potrebbe essere maggiore.

Il test ha confrontato ciascuna stringa in 1000 array di elementi, ripetuto 10 volte.


1
Immagino che tu debba aver usato stringhe molto corte, tutte della stessa lunghezza e con un'elevata diversità al primo carattere per ottenere un risultato dove compareTo()è più veloce di equals()? Ma per la maggior parte dei set di dati del mondo reale equals()è molto più veloce di compareTo() == 0. equals()brilla se le stringhe hanno un prefisso comune ma lunghezze diverse o se sono effettivamente lo stesso oggetto.
x4u

Bene, il mio test era contro l'ipotesi che l'istanza di prestazioni killer, quindi le corde erano davvero brevi.
Marinaio

Se la tua stringa è casuale e per lo più differisce in lunghezza, la scelta più ovvia dovrebbe essere il metodo equals () rispetto a compareTo () poiché nella maggior parte dei casi restituirà immediatamente false se non sono uguali in lunghezza.
sactiw

1
  1. equalspuò prendere qualsiasi oggetto come parametro ma compareTopuò accettare solo String.

  2. quando viene a zero, compareToverrà generata un'eccezione

  3. quando vuoi sapere dove si verifica il diff, puoi usare compareTo.


compareTo può prendere qualsiasi oggetto come argomento. Come ha detto @apurva jadhav, comparable accetta un argomento generico. Se si implementa comaparable come Comparable <String>, è possibile utilizzare solo stringhe.
Gaurav Kumar

1
  • equals: richiesto per controllare l'uguaglianza e limitare i duplicati. Molte classi della libreria Java lo utilizzano nel caso in cui volessero trovare duplicati. es. HashSet.add(ob1)aggiungerà solo se non esiste. Quindi, se stai estendendo alcune classi come questa, sovrascrivi equals().

  • compareTo: necessario per l'ordinazione dell'elemento. Anche in questo caso per l'ordinamento stabile è necessaria l'uguaglianza, quindi c'è un ritorno 0.


0

È uguale a -

1- Sostituisci il metodo GetHashCode per consentire a un tipo di funzionare correttamente in una tabella hash.

2- Non lanciare un'eccezione nell'implementazione di un metodo Equals. Restituisce invece false per un argomento nullo.

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.

Le successive chiamate di x.Equals (y) restituiscono lo stesso valore a condizione che l'oggetto a cui fa riferimento xey non venga modificato.

x.Equals(null) returns false.

4- Per alcuni tipi di oggetti, è preferibile avere Equals test per l'uguaglianza dei valori invece dell'uguaglianza referenziale. Tali implementazioni di Equals restituiscono true se i due oggetti hanno lo stesso valore, anche se non sono la stessa istanza.

Per esempio -

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

Produzione :-

False
True

mentre confrontaTo -

Confronta l'istanza corrente con un altro oggetto dello stesso tipo e restituisce un numero intero che indica se l'istanza corrente precede, segue o si trova nella stessa posizione nell'ordinamento dell'altro oggetto.

Ritorna -

Minore di zero: questa istanza precede obj nell'ordinamento. Zero: questa istanza si trova nella stessa posizione nell'ordinamento di obj. Maggiore di zero: questa istanza segue obj nell'ordinamento.

Può generare ArgumentException se l'oggetto non è dello stesso tipo dell'istanza.

Ad esempio puoi visitare qui.

Quindi suggerisco di usare meglio Equals al posto di compareTo.


Non esiste un GetHashCode()metodo. Intendi hashCode()?
Marchese di Lorne

0

"è uguale a" confronta oggetti e restituisce vero o falso e "confronta con" restituisce 0 se è vero o un numero [> 0] o [<0] se è falso ecco un esempio:

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

risultati:

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

Documentazione a confronto con: https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

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


0

Qui una cosa è importante durante l'utilizzo di compareTo()over equals()che compareTofunziona per le classi che implementano l'interfaccia 'Comparable' altrimenti lancerà un file NullPointerException. Stringclassi implementa l'interfaccia Comparable mentre StringBuffernon è quindi possibile utilizzarla "foo".compareTo("doo")in Stringobject ma non in StringBufferObject.


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

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

Questo stampa -2 e falso

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

Questo stampa 2 e falso

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

Questo stampa 0 e vero

equals restituisce booleano se e solo se entrambe le stringhe corrispondono.

compareTo non solo per dire se corrispondono, ma anche per dire quale stringa è minore dell'altra, e anche di quanto, lessicograficamente. Viene utilizzato principalmente durante l'ordinamento nella raccolta.


-1

Credo equalse equalsIgnoreCasemetodi di Stringritorno truee falseche è utile se si desidera confrontare i valori dell'oggetto stringa, ma in caso di implementazione compareToe compareToIgnoreCasemetodi restituisce valore positivo, negativo e zero che saranno utili in caso di ordinamento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.