CompareTo() vs. equals()

在 Java 中测试 String的相等性时,我总是使用 equals(),因为对我来说,这似乎是最自然的方法。毕竟,它的名字已经说明了它的意图。然而,我的一个同事最近告诉我,他们教我使用 compareTo() == 0而不是 equals()。这让我感觉很不自然(因为 compareTo()意味着提供一个排序,而不是为了平等而进行比较) ,甚至有些危险(因为 compareTo() == 0并不一定意味着在所有情况下都是平等的,尽管我知道对于 String来说是这样的)。

他不知道为什么他被教导使用 compareTo()而不是 equals()作为 String,我也找不到任何原因。这真的是个人喜好的问题吗? 或者这两种方法都有什么真正的原因吗?

211488 次浏览

看起来这两个方法做的事情基本相同,但 compareTo ()方法接受一个 String 而不是一个 Object,并在普通的 equals ()方法之上添加了一些额外的功能。如果您只关心相等性,那么 equals ()方法是最佳选择,原因很简单,因为它对下一个查看您的代码的程序员更有意义。这两个不同函数之间的时间差应该没有关系,除非您要循环处理大量的项。当您需要知道集合中 String 的顺序或者需要知道以相同字符序列开头的字符串之间的长度差时,compareTo ()非常有用。

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

两个主要区别是:

  1. equals将采用任何 Object 作为参数,但是 compareTo将只采用 String。
  2. equals只告诉你它们是否相等,但是 compareTo提供了字符串如何在字典上进行比较的信息。

我看了一下 字符串类代码,compareTo 和 equals 中的算法看起来基本相同。我相信他的观点只是品味的问题,我同意你的观点——如果你需要知道的只是字符串的相等性,而不是从词典学的角度来看,哪个字符串最先出现,那么我会使用 equals

当比较相等时,您应该使用 equals(),因为它以一种清晰的方式表达您的意图。

compareTo()还有一个额外的缺点,那就是它只能在实现 Comparable接口的对象上工作。

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

区别在于,"foo".equals((String)null)返回 false,而 "foo".compareTo((String)null) == 0抛出 NullPointerException。因此,即使对于 String,它们也不总是可以互换的。

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

compareTo()不仅适用于 String,还适用于任何其他对象,因为 compareTo<T>采用泛型参数 T。String 是通过实现 Comparable接口实现 compareTo()方法的类之一。所以任何类都可以自由地实现 Compable 接口。

但是 compareTo()给出了对象 的顺序,通常用于按升序或降序对对象进行排序,而 equals()只讨论等式表示它们是否相等。

String.equals()需要调用 instanceof操作符,而 compareTo()不需要。我的同事已经注意到在 equals()方法中由于 instanceof调用过多而导致的大量性能下降,但是我的测试已经证明 compareTo()只是稍微快一点。

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

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

在 Java 中覆盖 compareTo 时,有些事情你需要记住,例如 compareTo 必须与 equals 保持一致,并且不应该用减法来比较整数字段,因为它们可能会溢出。详情请参阅 在 Java 中重写 Compator 时需要记住的事情

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

  2. 当为 null 时,compareTo将抛出异常

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

在字符串上下文中:
compareTo: 按字典法比较两个字符串。
Equals: 将此字符串与指定的对象进行比较。 < br >

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

在 OP 的情况下,equals()应该是选择的方法。

看看 Lang. grepcode 上的字符串equals()compareTo()的实现,我们可以很容易地看到,如果我们只考虑两个字符串的相等性,等号会更好:

返回文章页面

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 = count;
1019 if (n == anotherString.count) {
1020 char v1[] = value;
1021 char v2[] = anotherString.value;
1022 int i = offset;
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 }

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 if (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 if (c1 != c2) {
1190 return 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 return c1 - c2;
1200 }
1201 }
1202 }
1203 return len1 - len2;
1204 }

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

在我看来,我们应该按照他们的意图来使用这两种方法:

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

这是一个巫术的实验: -)

大多数答案都会比较性能和 API 的差异,而忽略了这两个操作只是语义不同这一基本点。

你的直觉是正确的. x.equals (y)不能与 x.compareTo (y) = = 0互换。 前者比较同一性,而后者比较“大小”的概念。的确,在许多情况下,尤其是对于基元类型,这两种类型是共同对齐的。

一般情况是这样的:

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

但是,如果 x 和 y 具有相同的大小,这并不意味着它们是相同的。

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

身份不同于大小的一个引人注目的例子是复数。假设比较是通过它们的绝对值来完成的。所以给出两个复数: Z1 = a1 + b1 * i 和 Z2 = a2 + b2 * i:

Equals (z2)返回 true 当且仅当 a1 = a2和 b1 = b2。

然而,Z1.compareTo (Z2)只要满足条件 a1 ^ 2 + b1 ^ 2 = = a2 ^ 2 + b2 ^ 2,就会对(a1,b1)和(a2,b2)对返回0,并且返回无穷多个(a1,b1)和(a2,b2)对。

等于-

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

2-不要在 Equals 方法的实现中抛出异常。相反,对于 null 参数返回 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.

对于某些类型的对象,最好使用 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

相比之下

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

它返回-

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

如果 object 与 instance 的类型不同,它可以引发 ArgumentException。

例如,你可以访问这里。

所以我建议用 Equals 代替 compareTo。

  • 返回文章页面 检查相等性和限制重复所必需的。许多 JavaLibrary 类使用这种方法来查找副本。例如,HashSet.add(ob1)只有在不存在的情况下才会添加。因此,如果您正在像这样扩展一些类,那么覆盖 equals()

  • 返回文章页面 对于元素的排序,同样的,对于稳定的排序,需要等式,所以返回值是0。

“ equals”比较对象并返回 true 或 false 如果返回0为真或者数字[ > 0]或者[ < 0]为假,则返回0 举个例子:

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

平等比比较更有效率。

如果字符串中字符序列的长度不匹配,那么字符串就不可能相等,因此拒绝会快得多。

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

如果他们也实现了 hashCode 缓存,那么在 hashCode 不匹配的情况下拒绝非等式会更快。

Equals () 可能比 相比之下更有效。

比较和平等之间一个非常重要的区别:

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

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

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

注意,equals ()不定义对象之间的顺序,compareTo ()定义对象之间的顺序。

现在我建议你们回顾一下这两个方法的源代码,得出结论,等于优于比较,这涉及到一些数学计算。

Equals ()检查两个字符串是否相等,它给出布尔值。 CompareTo ()检查字符串对象是否等于、大于或小于另一个字符串对象: 如果字符串对象大于 如果两者相等,则为0 如果字符串比其他字符串小,则为 -1

问:

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

在使用 compareTo() over equals()时,有一点很重要,那就是 compareTo适用于实现“ Compaable”接口的类,否则它将抛出一个 NullPointerExceptionString类实现了可比较接口,而 StringBuffer没有,因此您可以在 String对象中使用 "foo".compareTo("doo"),但是在 StringBuffer对象中不能使用 "foo".compareTo("doo")

我认为 StringequalsequalsIgnoreCase方法返回 truefalse,如果你想比较字符串对象的值,这是有用的,但在实现 compareTocompareToIgnoreCase方法返回正值,负值和零值,这将是有用的情况下排序。

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 的意思不仅仅是说明它们是否匹配,还要说明哪个字符串比另一个字符串小,还要说明按字典顺序排列的字符串数量。这通常是在集合中进行排序时使用的。