compareTo()与equals()


118

String在Java中测试的相等性时,我一直使用,equals()因为对我而言,这似乎是最自然的方法。毕竟,它的名字已经说明了它打算做什么。但是,我的一位同事最近告诉我,有人教我使用compareTo() == 0代替equals()。这对我来说感觉很不自然(这compareTo()是为了提供顺序而不是为了比较而不是比较平等),甚至有些危险(因为compareTo() == 0不一定在所有情况下都意味着平等,即使我知道这样做对于String)。

他不知道为什么要教他compareTo()代替equals()for 来使用String,我也找不到任何原因。这真的是个人喜好问题,还是使用这两种方法的真正原因?


9
严格地说,在微优化级别上(.equalsIgnoreCase()如果我们合适的话)是最快的比较,否则.equals(),这就是您想要的。

1
这是一个古老的问题,但其中包含一个我想强调的点:“ compareTo() == 0不一定在所有情况下都意味着平等”。这是绝对正确的!这正是Java API规范(例如,Comparable类规范)中的“与等于一致”一词的含义。例如,String的比较方法与equals一致,但是BigDecimal的比较方法与equals 不一致
Stuart Marks

Answers:


104

不同之处在于,"foo".equals((String)null)"foo".compareTo((String)null) == 0抛出NullPointerException时返回false 。因此,即使对于字符串,它们也不总是可互换的。


6
我想您也应该提一下。等于计算哈希码。尽管很罕见,但两个不同字符串的哈希码可以相同。但是,当使用compareTo()时,它将逐字符检查字符串。因此,在这种情况下,当且仅当它们的实际内容相等时,两个字符串才返回true。
Ashwin'6

30
您为什么认为等于计算哈希码?您会发现情况并非如此:docjar.com/html/api/java/lang/String.java.html(第1013行)。
蜡翼

3
你是对的。我认为equals和hashcode齐头并进(equals检查两者是否具有相同的hash码)。那么,如果您决定覆盖这两种方法中的任何一种,则为什么必须覆盖这两种方法。
Ashwin 2012年

3
当我们覆盖等于时,有必要覆盖哈希码,因为如果类使用基于哈希的集合,包括HashMap,HashSet和Hashtable,则该类将无法正常运行
varunthacker 2012年

4
@Ashwin这是必要的,因为如果.equals返回true,则哈希码也应该相等。但是,如果哈希码相等,则并不意味着.equals应该返回true
Alan

33

2个主要区别是:

  1. equals将任何对象作为参数,但compareTo仅将字符串作为参数。
  2. equals仅告诉您它们是否相等,但compareTo提供有关字符串如何按字典顺序进行比较的信息。

我看了一看String类代码,compareTo和equals中的算法看起来基本相同。我相信他的意见只是一种品味问题,我同意您的看法-如果您只需要了解Strings的相等性,而不是首先按字典顺序出现的相等性,那么我会使用equals


26

比较是否相等时,应使用equals(),因为它可以清楚地表达您的意图。

compareTo()另一个缺点是,它仅对实现Comparable接口的对象起作用。

通常,这不仅适用于字符串。


18

compareTo如果字符串的长度不同,则可以做更多的工作。equals只能返回false,而compareTo必须始终检查足够的字符以找到排序顺序。


10

compareTo()不仅适用于字符串,而且适用于任何其他对象,因为compareTo<T>采用了通用参数T。字符串是compareTo()通过实现Comparable接口来实现方法的类之一。(compareTo()是可比接口的方法)。因此,任何类都可以自由实现Comparable接口。

但是compareTo()给出对象的顺序,通常用于按升序或降序对对象进行排序,而equals()仅讨论相等性并说它们是否相等。


10

在字符串上下文中:
compareTo:按字典顺序比较两个字符串。
等于:将此字符串与指定对象进行比较。

compareTo比较两个字符串的字符(在相同索引处),并相应地返回一个整数(正数或负数)。

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()可能比compareTo()更有效。

compareTo和equals之间非常重要的区别:

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

equals()检查两个对象是否相同,并返回一个布尔值。

相比于()(来自Comparable接口)返回一个整数。它检查两个对象中的哪个“小于”,“等于”或“大于”另一个。并非所有对象都可以在逻辑上排序,因此compareTo()方法并不总是有意义。

请注意,equals()并未定义对象之间的顺序,compareTo()却如此。

现在,我建议您检查两种方法的源代码,得出结论,等于equals比涉及某些Math计算的compareTo更可取。


5

看起来这两个方法几乎都做相同的事情,但是compareTo()方法采用String而不是Object,并且在常规equals()方法之上添加了一些额外的功能。如果您只关心相等,那么equals()方法是最佳选择,因为对下一个查看您的代码的程序员来说,它更有意义。除非您要遍历大量项目,否则两个不同函数之间的时间差异并不重要。当您需要了解集合中字符串的顺序,或者需要了解以相同字符序列开头的字符串之间的长度差异时,compareTo()确实很有用。

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


5

equals() 对于OP,应该选择该方法。

查看grepcodejava.lang.Stringequals()compareTo()中的实现,如果我们只关心两个字符串的相等性,我们可以很容易地发现equals更好:

equals()

1012   public  boolean equals(Object anObject){ 
1013 ifthis == anObject){
1014 return true ;
1015 }
1016 if(anObject instanceof String){
1017 String anotherString =(String)anObject;
1018 整数 n = count;
1019 if(n == anotherString.count){
1020 char v1 [] = value;
1021 char v2 [] = anotherString.value;
1022 INTi =偏移量;
1023 int j = anotherString.offset;
1024 while(n--!= 0){
1025 if(v1 [i ++]!= v2 [j ++])
1026 返回 false ;
1027 }
1028 返回 true ;
1029 }
1030 }
1031 返回 false ;
1032 }

compareTo()

1174   public  int compareTo(String anotherString){ 
1175 int len1 =计数;
1176 INT LEN2 = anotherString.count;
1177 int n =数学 min(len1,len2);
1178 char v1 [] =值;
1179 char v2 [] = anotherString.value;
1180 int =偏移量
1181 int j = anotherString.offset;
1183 如果(I == j)的{
1184 INT K = 1;
1185 int lim = n +我;
1186年, (k <lim){
1187个 字符c1 = v1 [k];
1188 char c2 = v2 [k];
1189 如果(C1 = C2!){
1190 返回 C1 - C2;
1191 }
1192 k ++;
1193 }
1194 } else {
1195 while(n--!= 0){
1196 char c1 = v1 [i ++];
1197 char c2 = v2 [j ++];
1198 如果(C1 = C2!){
1199 返回 C1 - C2;
1200 }
1201 }
1202 }
1203 返回len1-len2;
1204 }

当其中一个字符串是另一个字符串的前缀时,的性能compareTo()较差,因为它仍然需要确定字典顺序,而equals()不必担心,并立即返回false。

我认为,我们应该按预期使用这两个:

  • equals() 检查是否平等,以及
  • compareTo() 查找词汇顺序。

3

equals()检查两个字符串是否相等,给出布尔值。compareTo()检查一个字符串对象是否等于,大于或小于另一个字符串对象。结果为:1如果字符串对象大于0,如果两个都等于-1,如果字符串小于其他字符串

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

这是死灵法的实验:-)

大多数答案会比较性能和API差异。他们错过了两个操作仅具有不同语义的基本要点。

你的直觉是正确的。x.equals(y)不能与x.compareTo(y)== 0互换。第一个比较身份,而另一个比较“大小”的概念。的确,在许多情况下,尤其是在使用原始类型的情况下,这两者是并列的。

一般情况是这样的:

如果x和y相同,则它们共享相同的“大小”:如果x.equals(y)为true => x.compareTo(y)为0。

但是,如果x和y共享相同的大小,并不表示它们是相同的。

如果x.compareTo(y)为0,则不一定意味着x.equals(y)为true。

身份与规模不同的一个令人信服的例子是复数。假设比较是通过它们的绝对值完成的。因此,给定两个复数:Z1 = a1 + b1 * i和Z2 = a2 + b2 * i:

当且仅当a1 = a2和b1 = b2时,Z1.equals(z2)返回true。

但是,只要满足条件a1 ^ 2 + b1 ^ 2 == a2 ^ 2 + b2 ^ 2,Z1.compareTo(Z2)就会返回0,并且无限数量的(a1,b1)和(a2,b2)对会返回。


1
x.equals(y)不表示身份,而是表示平等。对于Java中用户定义的类型,使用x == y比较身份。
Fernando Pelliccioni 2014年

2

等于可以比compareTo更有效。

如果字符串中字符序列的长度不匹配,则字符串相等是不可能的,因此拒绝会更快。

而且,如果它是同一个对象(身份相等而不是逻辑相等),它将也更有效率。

如果他们还实现了hashCode缓存,则在他们的hashCode不匹配的情况下,拒绝不等值甚至更快。


2

String.equals()需要调用instanceof运算符,而不compareTo()需要。我的同事注意到方法instanceof调用过多导致性能大幅下降equals(),但是我的测试证明compareTo()仅稍快一点。

但是,我使用的是Java 1.6。在其他版本(或其他JDK供应商)上,差异可能更大。

测试比较了1000个元素数组中的每个字符串,重复了10次。


1
我猜您必须在第一个字符上使用非常短的字符串,并且长度都一样,且多样性很高,才能compareTo()equals()?更快地得到结果。但是对于大多数现实世界数据而言,equals()它的速度要快得多compareTo() == 0equals()如果字符串具有相同的前缀但长度不同,或者它们实际上是同一对象,则发光。
2011年

好吧,我的测试是反对instanceof是性能杀手的假设,因此字符串确实很短。
Danubian Sailor'Jun

如果您的字符串是随机的,并且长度不同,那么比较明显的选择应该是equals()方法而不是compareTo(),因为在大多数情况下,如果长度不相等,它将立即返回false。
sactiw

1
  1. equals可以接受任何Object作为参数,但compareTo只能接受String。

  2. 当cometo为null时,compareTo将引发异常

  3. 当您想知道差异发生在哪里时,可以使用compareTo


compareTo可以将任何对象用作参数。正如@apurva jadhav所说的,comparison采用了通用的论点。如果将可比较实现为Comparable <String>,则仅允许使用字符串。
Gaurav Kumar

1
  • equals:检查相等性和限制重复项时必需。Java库的许多类在需要查找重复项时都使用此方法。例如,HashSet.add(ob1)仅在不存在时添加。因此,如果要扩展这样的某些类,则可以重写equals()

  • compareTo:元素订购必需。同样,为了进行稳定的排序,您需要相等,因此返回0。


0

等于 -

1-重写GetHashCode方法,以允许类型在哈希表中正常工作。

2-在Equals方法的实现中不要抛出异常。相反,对于空参数返回false。

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.

只要不修改x和y引用的对象,x.Equals(y)的连续调用将返回相同的值。

x.Equals(null) returns false.

4-对于某些类型的对象,希望对值相等性进行Equals测试,而不要对引用相等性进行测试。如果两个对象具有相同的值,即使它们不是相同的实例,这种Equals的实现也会返回true。

例如 -

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

输出:-

False
True

compareTo-

将当前实例与相同类型的另一个对象进行比较,并返回一个整数,该整数指示当前实例是在其他对象的排序顺序的前面,之后还是在相同的位置。

它返回-

小于零-此实例按排序顺序在obj之前。零-此实例与obj的排序顺序相同。大于零-此实例按排序顺序跟随obj。

如果object与实例的类型不同,则可能引发ArgumentException。

例如,您可以在这里访问。

因此,我建议最好使用Equals代替compareTo。


没有GetHashCode()办法。你是说hashCode()
罗恩侯爵,

0

“等于”比较对象并返回true或false,如果为true,则“ compare to”返回0,如果为false,则返回数字[> 0]或[<0],如果此处为false:

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

结果:

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

文档进行比较:https : //docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

文档等于:https ://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals( java.lang.Object)


0

在这里,有一点很重要,那就是使用compareTo()over equals()compareTo实现实现“可比较”接口的类,否则它将抛出NullPointerExceptionString类实现Comparable接口,但不能在对象中StringBuffer使用"foo".compareTo("doo")String而不能在StringBuffer对象中使用。


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

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

这打印-2和false

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

打印2和false

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

这将输出0和true

当且仅当两个字符串匹配时,equals才返回布尔值。

compareTo的意思是不仅要判断它们是否匹配,而且还要按字典顺序判断哪个String比另一个String小。这通常在集合排序时使用。


-1

我相信equalsequalsIgnoreCase方法String的返回truefalse它是,如果你想比较字符串对象的值是有用的,但在实施的情况compareTocompareToIgnoreCase方法返回正数,负数和零值将在排序的情况下是有用的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.