compareTo () vs. equals ()

118

Ao testar a igualdade de String's em Java, sempre usei equals()porque para mim esse parece ser o método mais natural para isso. Afinal, o nome já diz o que pretende fazer. No entanto, um colega meu recentemente me disse que havia sido ensinado a usar em compareTo() == 0vez de equals(). Isso parece não natural (visto que compareTo()se destina a fornecer uma ordem e não comparar para igualdade) e até um pouco perigoso (porque compareTo() == 0não implica necessariamente igualdade em todos os casos, embora eu saiba que significa para String's) para mim.

Ele não sabia por que foi ensinado a usar em compareTo()vez de equals()para String, e também não consegui encontrar nenhuma razão para isso. É realmente uma questão de gosto pessoal ou existe alguma razão real para qualquer um dos métodos?

Thomas Lötzer
fonte
9
Estritamente falando, em um nível de micro-otimização, do qual nunca devemos falar prematuramente, .equalsIgnoreCase()é a comparação mais rápida se for apropriado, caso contrário, .equals()é o que você deseja.
1
Esta é uma questão antiga, mas contém uma pepita que gostaria de destacar: " compareTo() == 0não implica necessariamente igualdade em todos os casos". Isso é absolutamente correto! Isso é exatamente o que a frase "consistente com igual" significa nas especificações da API Java, por exemplo, na especificação da classe Comparable . Por exemplo, o método de comparação de String é consistente com igual, mas o método de comparação de BigDecimal é inconsistente com igual.
Stuart Marks em

Respostas:

104

A diferença é que "foo".equals((String)null)retorna falso enquanto "foo".compareTo((String)null) == 0lança uma NullPointerException. Portanto, eles nem sempre são intercambiáveis, mesmo para Strings.

asa de cera
fonte
6
Eu acho que você também deve mencionar isso. igual a calcula o código hash. O hashcode de duas strings diferentes, embora raro, pode ser o mesmo. Mas ao usar compareTo (), ele verifica as strings caractere por caractere. Portanto, neste caso, duas strings retornarão true se e somente se seus conteúdos reais forem iguais.
Ashwin
30
Por que você acha que igual calcula o código hash? Você pode ver que este não é o caso: docjar.com/html/api/java/lang/String.java.html (linha 1013).
waxwing
3
você está certo. Eu pensei que igual e hashcode andam de mãos dadas (equals verifica se ambos têm o mesmo código hash). Então, por que é necessário substituir esses dois métodos se você decidir substituir qualquer um deles.
Ashwin
3
É necessário substituir o hashcode quando substituímos equals porque se a classe usar coleções baseadas em hash, incluindo HashMap, HashSet e Hashtable, a classe não funcionará corretamente
varunthacker
4
@Ashwin É necessário porque se .equals retornar verdadeiro, os hashcodes também devem ser iguais. No entanto, se os hashcodes forem iguais, isso não significa que .equals deva retornar verdadeiro
Alan
33

As 2 principais diferenças são:

  1. equalstomará qualquer objeto como parâmetro, mas compareTosó aceitará Strings.
  2. equalsapenas informa se eles são iguais ou não, mas compareTofornece informações sobre como as Strings são comparadas lexicograficamente.

Dei uma olhada no código da classe String , e o algoritmo em compareTo e equals parece basicamente o mesmo. Acredito que a opinião dele foi apenas uma questão de gosto e concordo com você - se tudo o que você precisa saber é a igualdade das cordas e não qual vem primeiro lexicograficamente, então eu usaria equals.

Kaleb Brasee
fonte
26

Ao comparar por igualdade, você deve usar equals(), porque expressa sua intenção de forma clara.

compareTo() tem a desvantagem adicional de funcionar apenas em objetos que implementam o Comparable interface.

Isso se aplica em geral, não apenas para Strings.

azul da estrela
fonte
18

compareTotem fazer mais trabalho se as cordas tiverem comprimentos diferentes. equalspode apenas retornar falso, enquanto compareTodeve sempre examinar caracteres suficientes para encontrar a ordem de classificação.

Robinr
fonte
10

compareTo()não se aplica apenas a Strings, mas também a qualquer outro objeto porque compareTo<T>leva um argumento genérico T. String é uma das classes que implementou o compareTo()método implementando a Comparableinterface. (compareTo () é um método para a Interface comparável).Portanto, qualquer classe está livre para implementar a interface Comparable.

Mas compareTo()dá a ordenação de objetos , usada normalmente na classificação de objetos em ordem crescente ou decrescente enquanto equals()só vai falar sobre a igualdade e dizer se eles são iguais ou não.

apurva jadhav
fonte
10

No contexto da string:
compareTo: Compara duas strings lexicograficamente.
é igual a: compara esta string com o objeto especificado.

compareTo compara duas strings por seus caracteres (no mesmo índice) e retorna um inteiro (positivo ou negativo) de acordo.

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
fonte
7

equals () pode ser mais eficiente do que compareTo () .

Uma diferença muito importante entre compareTo e equals:

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

equals () verifica se dois objetos são iguais ou não e retorna um booleano.

comparado a() (da interface Comparable) retorna um inteiro. Ele verifica qual dos dois objetos é "menor que", "igual a" ou "maior que" o outro. Nem todos os objetos podem ser ordenados logicamente, portanto, um método compareTo () nem sempre faz sentido.

Observe que equals () não define a ordem entre objetos, o que compareTo () faz.

Agora, aconselho você a revisar o código-fonte de ambos os métodos para concluir que equals é preferível a compareTo, que envolve alguns cálculos matemáticos.

Jaimin Patel
fonte
5

Parece que os dois métodos fazem praticamente a mesma coisa, mas o método compareTo () usa uma String, não um Object, e adiciona algumas funcionalidades extras ao método equals () normal. Se você só se preocupa com a igualdade, o método equals () é a melhor escolha, simplesmente porque faz mais sentido para o próximo programador que examinar seu código. A diferença de tempo entre as duas funções diferentes não deve importar, a menos que você esteja percorrendo uma grande quantidade de itens. O compareTo () é realmente útil quando você precisa saber a ordem das Strings em uma coleção ou quando você precisa saber a diferença de comprimento entre as strings que começam com a mesma sequência de caracteres.

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

Scott M.
fonte
5

equals() deve ser o método de escolha no caso do OP.

Olhando para a implementação de equals()e compareTo()em java.lang.String no grepcode , podemos facilmente ver que igual é melhor se estivermos apenas preocupados com a igualdade de duas Strings:

equals():

1012   public  boolean equals ( objeto anObject) { 
1013 if ( this == anObject) {
1014 return true ;
1015 }
1016 if (uma instância de Objeto de String ) {
1017 String anotherString = ( String ) anObject;
1018 int n = contagem;
1019 if (n == anotherString.count) {
1020 char v1 [] = value;
1021 char v2 [] = anotherString.value;
1022 inti = deslocamento;
1023 int j = anotherString.offset;
1024 while (n--! = 0) {
1025 if (v1 [i ++]! = V2 [j ++])
1026 return false ;
1027 }
1028 retornar verdadeiro ;
1029 }
1030 }
1031 retornam falso ;
1032 }

e compareTo():

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

Quando uma das strings é prefixo de outra, o desempenho de compareTo()é pior, pois ainda precisa determinar a ordem lexicográfica enquanto equals()não se preocupa mais e retorna falso imediatamente.

Em minha opinião, devemos usar esses dois como foram planejados:

  • equals() para verificar a igualdade, e
  • compareTo() para encontrar a ordem lexical.
prk
fonte
3

equals () verifica se duas strings são iguais ou não. Fornece um valor booleano. compareTo () verifica se o objeto string é igual, maior ou menor ao outro objeto string. Ele dá o resultado como: 1 se o objeto string for maior 0 se ambos forem iguais a -1 se string for menor que outra string

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
fonte
2

Há certas coisas que você precisa manter em mente ao substituir compareTo em Java, por exemplo, Compareto deve ser consistente com igual e a subtração não deve ser usada para comparar campos inteiros, pois eles podem estourar. verifique Coisas a lembrar ao substituir Comparator em Java para obter detalhes.

Seema Kiran
fonte
2

Este é um experimento em necromancia :-)

A maioria das respostas compara diferenças de desempenho e API. Eles perdem o ponto fundamental de que as duas operações simplesmente têm semânticas diferentes.

Sua intuição está correta. x.equals (y) não é intercambiável com x.compareTo (y) == 0. O primeiro compara a identidade, enquanto o outro compara a noção de 'tamanho'. É verdade que em muitos casos, especialmente com tipos primitivos, esses dois se alinham.

O caso geral é este:

Se x e y forem idênticos, eles compartilham o mesmo 'tamanho': se x.equals (y) for verdadeiro => x.compareTo (y) é 0.

No entanto, se xey compartilham o mesmo tamanho, isso não significa que sejam idênticos.

se x.compareTo (y) for 0, não significa necessariamente que x.equals (y) seja verdadeiro.

Um exemplo atraente em que a identidade difere do tamanho são os números complexos. Suponha que a comparação seja feita por seu valor absoluto. Portanto, dados dois números complexos: Z1 = a1 + b1 * i e Z2 = a2 + b2 * i:

Z1.equals (z2) retorna verdadeiro se e somente se a1 = a2 e b1 = b2.

No entanto, Z1.compareTo (Z2) retorna 0 para um número infinito de (a1, b1) e (a2, b2) pares, desde que satisfaçam a condição a1 ^ 2 + b1 ^ 2 == a2 ^ 2 + b2 ^ 2.

Vitaliy
fonte
1
x.equals (y) não significa identidade, significa igualdade. A identidade é comparada usando x == y para tipos definidos pelo usuário em Java.
Fernando Pelliccioni
2

Equals pode ser mais eficiente do que compareTo.

Se o comprimento das sequências de caracteres em String não corresponder, não há como as Strings serem iguais, então a rejeição pode ser muito mais rápida.

Além disso, se for o mesmo objeto (igualdade de identidade em vez de igualdade lógica), também será mais eficiente.

Se eles também implementassem o cache de hashCode, poderia ser ainda mais rápido rejeitar não iguais no caso de seus hashCode não corresponderem.

Gopal Rajpurohit
fonte
2

String.equals()requer a chamada do instanceofoperador, enquanto compareTo()não requer. Meu colega notou uma grande queda no desempenho causada por um número excessivo de instanceofchamadas no equals()método, mas meu teste provoucompareTo() ser apenas um pouco mais rápido.

Eu estava usando, no entanto, Java 1.6. Em outras versões (ou outros fornecedores de JDK), a diferença pode ser maior.

O teste comparou cada string em matrizes de 1000 elementos, repetidas 10 vezes.

Marinheiro danubiano
fonte
1
Eu acho que você deve ter usado strings muito curtas, todas do mesmo comprimento e com alta diversidade no primeiro caractere para obter um resultado onde compareTo()é mais rápido do que equals()? Mas para a maioria dos conjuntos de dados do mundo real equals()é muito mais rápido do que compareTo() == 0. equals()brilha se as strings têm um prefixo comum, mas comprimentos diferentes ou se são realmente o mesmo objeto.
x4u
Bem, meu teste foi contra a hipótese de que a instância é destruidora do desempenho, então as cordas eram realmente curtas.
Marinheiro Danubiano
Se sua string é aleatória e difere principalmente em comprimento, então a escolha mais óbvia deve ser o método equals () em vez de compareTo (), pois na maioria dos casos ele retornará imediatamente falso se eles não forem iguais em comprimento.
sactiw
1
  1. equalspode aceitar qualquer objeto como parâmetro, mas compareTosó pode aceitar String.

  2. quando chegar a nulo, compareTolançará uma exceção

  3. quando você quiser saber onde a diferença acontece, você pode usar compareTo.

Tigre pequeno
fonte
compareTo pode tomar qualquer objeto como argumento. Como @apurva jadhav disse acima, comparável leva um argumento genérico. Se você implementar comaparable como Comparable <String>, terá permissão para usar apenas strings.
Gaurav Kumar
1
  • equals: necessário para verificar a igualdade e restringir duplicatas. Muitas classes da Biblioteca Java usam isso no caso de quererem encontrar duplicatas. por exemplo HashSet.add(ob1), só adicionará se isso não existir. Portanto, se você estiver estendendo algumas classes como essa, substitua equals().

  • compareTo: necessário para o pedido do elemento. Novamente, para classificação estável, você precisa de igualdade, portanto, há um retorno 0.

Dillip Rout
fonte
0

É igual a -

1- Substitua o método GetHashCode para permitir que um tipo funcione corretamente em uma tabela hash.

2- Não lance uma exceção na implementação de um método Equals. Em vez disso, retorne false para um 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.

As invocações sucessivas de x.Equals (y) retornam o mesmo valor, desde que o objeto referenciado por xey não seja modificado.

x.Equals(null) returns false.

4- Para alguns tipos de objetos, é desejável ter o teste Equals para igualdade de valor em vez de igualdade referencial. Essas implementações de Equals retornam true se os dois objetos tiverem o mesmo valor, mesmo se não forem a mesma instância.

Por exemplo -

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

Resultado :-

False
True

enquanto compareTo -

Compara a instância atual com outro objeto do mesmo tipo e retorna um inteiro que indica se a instância atual precede, segue ou ocorre na mesma posição na ordem de classificação que o outro objeto.

Ele retorna -

Menor que zero - esta instância precede obj na ordem de classificação. Zero - esta instância ocorre na mesma posição na ordem de classificação que obj. Maior que zero - esta instância segue obj na ordem de classificação.

Ele pode lançar ArgumentException se o objeto não for do mesmo tipo que a instância.

Por exemplo, você pode visitar aqui.

Portanto, sugiro usar Equals em vez de compareTo.

Prabhat Jain
fonte
Não existe GetHashCode()método. Você quer dizer hashCode()?
Marquês de Lorne
0

"igual" compara objetos e retorna verdadeiro ou falso e "comparar com" retorna 0 se for verdadeiro ou um número [> 0] ou [<0] se for falso aqui um exemplo:

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

Documentação Compare com: https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

Documentação igual a: https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)

David Hackro
fonte
0

Aqui, uma coisa é importante ao usar compareTo()over equals()que compareTofunciona para as classes que implementam a interface 'Comparable', caso contrário, ele gerará um NullPointerException. Stringclasses implementa interface Comparable enquanto StringBuffernão, portanto, você pode usar "foo".compareTo("doo")em Stringobjeto, mas não em StringBufferobjeto.

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

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

Isso imprime -2 e falso

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

Isso imprime 2 e falso

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

Isso imprime 0 e verdadeiro

equals retorna booleano se e somente se ambas as strings forem correspondentes.

compareTo destina-se não apenas a dizer se eles correspondem, mas também qual String é menor que a outra, e também por quanto, lexicograficamente. Isso é usado principalmente durante a classificação na coleção.

Deepak Selvakumar
fonte
-1

Eu acredito equalse equalsIgnoreCasemétodos de Stringretorno truee falseque é útil se você quiser comparar os valores do objeto string, mas em caso de implementação compareToe compareToIgnoreCasemétodos de retornos positivos, negativos e zero, valor que será útil em caso de classificação.

Prakhar Aditya
fonte