compareTo() vs. equals()

JavaStringEqualsCompareto

Java Problem Overview


When testing for equality of String's in Java I have always used equals() because to me this seems to be the most natural method for it. After all, its name already says what it is intended to do. However, a colleague of mine recently told me had been taught to use compareTo() == 0 instead of equals(). This feels unnatural (as compareTo() is meant to provide an ordering and not compare for equality) and even somewhat dangerous (because compareTo() == 0 does not necessarily imply equality in all cases, even though I know it does for String's) to me.

He did not know why he was taught to use compareTo() instead of equals() for String's, and I could also not find any reason why. Is this really a matter of personal taste, or is there any real reason for either method?

Java Solutions


Solution 1 - Java

A difference is that "foo".equals((String)null) returns false while "foo".compareTo((String)null) == 0 throws a NullPointerException. So they are not always interchangeable even for Strings.

Solution 2 - Java

The 2 main differences are that:

  1. equals will take any Object as a parameter, but compareTo will only take Strings.
  2. equals only tells you whether they're equal or not, but compareTo gives information on how the Strings compare lexicographically.

I took a look at the String class code, and the algorithm within compareTo and equals looks basically the same. I believe his opinion was just a matter of taste, and I agree with you -- if all you need to know is the equality of the Strings and not which one comes first lexicographically, then I would use equals.

Solution 3 - Java

When comparing for equality you should use equals(), because it expresses your intent in a clear way.

compareTo() has the additional drawback that it only works on objects that implement the Comparable interface.

This applies in general, not only for Strings.

Solution 4 - Java

compareTo has do do more work if the strings have different lengths. equals can just return false, while compareTo must always examine enough characters to find the sorting order.

Solution 5 - Java

In String Context:
compareTo: Compares two strings lexicographically.
equals: Compares this string to the specified object.

compareTo compares two strings by their characters (at same index) and returns an integer (positive or negative) accordingly.

String s1 = "ab";
String s2 = "ab";
String s3 = "qb";
s1.compareTo(s2); // is 0
s1.compareTo(s3); // is -16
s3.compareTo(s1); // is 16

Solution 6 - Java

compareTo() not only applies to Strings but also any other object because compareTo<T> takes a generic argument T. String is one of the classes that has implemented the compareTo() method by implementing the Comparable interface.(compareTo() is a method fo the comparable Interface). So any class is free to implement the Comparable interface.

But compareTo() gives the ordering of objects, used typically in sorting objects in ascending or descending order while equals() will only talk about the equality and say whether they are equal or not.

Solution 7 - Java

> equals() can be more efficient then compareTo().

A very important difference between compareTo and equals:

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

equals() checks if two objects are the same or not and returns a boolean.

compareTo() (from interface Comparable) returns an integer. It checks which of the two objects is "less than", "equal to" or "greater than" the other. Not all objects can be logically ordered, so a compareTo() method doesn't always make sense.

Note that equals() doesn't define the ordering between objects, which compareTo() does.

Now I advise you to review the source code of both methods to conclude that equals is preferable over compareTo that involves some Math calculations.

Solution 8 - Java

It appears that both methods pretty much do the same thing, but the compareTo() method takes in a String, not an Object, and adds some extra functionality on top of the normal equals() method. If all you care about is equality, then the equals() method is the best choice, simply because it makes more sense to the next programmer that takes a look at your code. The time difference between the two different functions shouldn't matter unless you're looping over some huge amount of items. The compareTo() is really useful when you need to know the order of Strings in a collection or when you need to know the difference in length between strings that start with the same sequence of characters.

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

Solution 9 - Java

equals() should be the method of choice in the case of the OP.

Looking at the implementation of equals() and compareTo() in java.lang.String on grepcode, we can easily see that equals is better if we are just concerned with the equality of two Strings:

equals():

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1012">1012</a>  public boolean equals(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Object.java#Object" title="java.lang.Object">Object anObject) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1013">1013</a> if (this == anObject) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1014">1014</a> return true;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1015">1015</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1016">1016</a> if (anObject instanceof http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" title="java.lang.String">String) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1017">1017</a> http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" title="java.lang.String">String anotherString = (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" title="java.lang.String">String)anObject;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1018">1018</a> int n = http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.0count" title="int count" class="hidden">count;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1019">1019</a> if (n == anotherString.count) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1020">1020</a> char v1[] = http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.0value" title="char[] value" class="hidden">value;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1021">1021</a> char v2[] = anotherString.value;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1022">1022</a> int i = http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.0offset" title="int offset" class="hidden">offset;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1023">1023</a> int j = anotherString.offset;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1024">1024</a> while (n-- != 0) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1025">1025</a> if (v1[i++] != v2[j++])
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1026">1026</a> return false;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1027">1027</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1028">1028</a> return true;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1029">1029</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1030">1030</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1031">1031</a> return false;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1032">1032</a> }

and compareTo():

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1174">1174</a>  public int compareTo(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" title="java.lang.String">String anotherString) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1175">1175</a> int len1 = http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.0count" title="int count" class="hidden">count;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1176">1176</a> int len2 = anotherString.count;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1177">1177</a> int n = Math.http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Math.java#Math.min%28int%2Cint%29" title="java.lang.Math.min(int,int) : int">min(len1, len2);
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1178">1178</a> char v1[] = http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.0value" title="char[] value" class="hidden">value;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1179">1179</a> char v2[] = anotherString.value;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1180">1180</a> int i = http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.0offset" title="int offset" class="hidden">offset;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1181">1181</a> int j = anotherString.offset;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1183">1183</a> if (i == j) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1184">1184</a> int k = i;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1185">1185</a> int lim = n + i;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1186">1186</a> while (k < lim) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1187">1187</a> char c1 = v1[k];
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1188">1188</a> char c2 = v2[k];
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1189">1189</a> if (c1 != c2) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1190">1190</a> return c1 - c2;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1191">1191</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1192">1192</a> k++;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1193">1193</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1194">1194</a> } else {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1195">1195</a> while (n-- != 0) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1196">1196</a> char c1 = v1[i++];
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1197">1197</a> char c2 = v2[j++];
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1198">1198</a> if (c1 != c2) {
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1199">1199</a> return c1 - c2;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1200">1200</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1201">1201</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1202">1202</a> }
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1203">1203</a> return len1 - len2;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1204">1204</a> }

When one of the strings is a prefix of another, the performance of compareTo() is worse as it still needs to determine the lexicographical ordering while equals() won't worry any more and return false immediately.

In my opinion, we should use these two as they were intended:

  • equals() to check for equality, and
  • compareTo() to find the lexical ordering.

Solution 10 - Java

equals() checks whether two strings are equal or not.It gives boolean value. compareTo() checks whether string object is equal to,greater or smaller to the other string object.It gives result as : 1 if string object is greater 0 if both are equal -1 if string is smaller than other 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

Solution 11 - Java

String.equals() requires invoking instanceof operator while compareTo() requires not. My colleague has noted large performance drop-down caused by excessive numbers of instanceof calls in equals() method, however my test has proved compareTo() to be only slightly faster.

I was using, however, Java 1.6. On other versions (or other JDK vendors) the difference could be larger.

The test compared each-to-each string in 1000 element arrays, repeated 10 times.

Solution 12 - Java

There are certain things which you need to keep in mind while overriding compareTo in Java e.g. Compareto must be consistent with equals and subtraction should not be used for comparing integer fields as they can overflow. check http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html">Things to remember while overriding Comparator in Java for details.

Solution 13 - Java

This is an experiment in necromancy :-)

Most answers compare performance and API differences. They miss the fundamental point that the two operations simply have different semantics.

Your intuition is correct. x.equals(y) is not interchangeable with x.compareTo(y) == 0. The first compares identity, while the other compares the notion of 'size'. It is true that in many cases, especially with primitive types, these two co-align.

The general case is this:

If x and y are identical, they share the same 'size': if x.equals(y) is true => x.compareTo(y) is 0.

However, if x and y share the same size, it does not mean they are identical.

if x.compareTo(y) is 0 does not necessarily mean x.equals(y) is true.

A compelling example where identity differs from size would be complex numbers. Assume that the comparison is done by their absolute value. So given two complex numbers: Z1 = a1 + b1i and Z2 = a2 + b2i:

Z1.equals(z2) returns true if and only if a1 = a2 and b1 = b2.

However Z1.compareTo(Z2) returns 0 for and infinite number of (a1,b1) and (a2,b2) pairs as long as they satisfy the condition a1^2 + b1^2 == a2^2 + b2^2.

Solution 14 - Java

Equals can be more efficient then compareTo.

If the length of the character sequences in String doesn't match there is no way the Strings are equal so rejection can be much faster.

Moreover if it is same object (identity equality rather then logical equality), it will also be more efficient.

If they also implemented hashCode caching it could be even faster to reject non-equals in case their hashCode's doesn't match.

Solution 15 - Java

  1. equals can take any Object as a parameter but compareTo can only take String.

  2. when cometo null,compareTo will throw a exception

  3. when you want to know where the diff happen,you can use compareTo.

Solution 16 - Java

  • equals: required for checking equality and restricting duplicates. Many classes of Java Library use this in case they wanted to find duplicates. e.g. HashSet.add(ob1) will only add if that doesn't exist. So if you are extending some classes like this then override equals().

  • compareTo: required for ordering of element. Again for stable sorting you require equality, so there is a return 0.

Solution 17 - Java

Equals -

1- Override the GetHashCode method to allow a type to work correctly in a hash table.

2- Do not throw an exception in the implementation of an Equals method. Instead, return false for a null argument.

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.

Successive invocations of x.Equals(y) return the same value as long as the object referenced by x and y are not modified.

x.Equals(null) returns false.

4- For some kinds of objects, it is desirable to have Equals test for value equality instead of referential equality. Such implementations of Equals return true if the two objects have the same value, even if they are not the same instance.

For Example -

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

Output :-

False
True

while compareTo -

Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.

It returns -

Less than zero - This instance precedes obj in the sort order. Zero - This instance occurs in the same position in the sort order as obj. Greater than zero - This instance follows obj in the sort order.

It can throw ArgumentException if object is not the same type as instance.

For example you can visit here.

So I suggest better to use Equals in place of compareTo.

Solution 18 - Java

"equals" compare objects and return true or false and "compare to" return 0 if is true or an number [> 0] or [< 0] if is false here an example:

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

Results:

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

Documentation Compare to: https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

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

Solution 19 - Java

Here one thing is important while using compareTo() over equals() that compareTo works for the classes that implements 'Comparable' interface otherwise it will throw a NullPointerException. String classes implements Comparable interface while StringBuffer does not hence you can use "foo".compareTo("doo") in String object but not in StringBuffer Object.

Solution 20 - Java

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

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

This prints -2 and false

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

This prints 2 and false

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

This prints 0 and true

equals returns boolean if and only if both strings match.

compareTo is meant to not just tell if they match but also to tell which String is lesser than the other, and also by how much, lexicographically. This is mostly used while sorting in collection.

Solution 21 - Java

I believe equals and equalsIgnoreCase methods of String return true and false which is useful if you wanted to compare the values of the string object, But in case of implementing compareTo and compareToIgnoreCase methods returns positive, negative and zero value which will be useful in case of sorting.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThomas L&#246;tzerView Question on Stackoverflow
Solution 1 - JavawaxwingView Answer on Stackoverflow
Solution 2 - JavaKaleb BraseeView Answer on Stackoverflow
Solution 3 - JavastarblueView Answer on Stackoverflow
Solution 4 - JavarobinrView Answer on Stackoverflow
Solution 5 - JavaVirtualLogicView Answer on Stackoverflow
Solution 6 - Javaapurva jadhavView Answer on Stackoverflow
Solution 7 - JavaJaimin PatelView Answer on Stackoverflow
Solution 8 - JavaScott M.View Answer on Stackoverflow
Solution 9 - JavaprkView Answer on Stackoverflow
Solution 10 - JavaAnkit UniyalView Answer on Stackoverflow
Solution 11 - JavaDanubian SailorView Answer on Stackoverflow
Solution 12 - JavaSeema KiranView Answer on Stackoverflow
Solution 13 - JavaVitaliyView Answer on Stackoverflow
Solution 14 - JavaGopal RajpurohitView Answer on Stackoverflow
Solution 15 - JavalittletigerView Answer on Stackoverflow
Solution 16 - JavaDillip RoutView Answer on Stackoverflow
Solution 17 - JavaPrabhat JainView Answer on Stackoverflow
Solution 18 - JavaDavid HackroView Answer on Stackoverflow
Solution 19 - JavaPratikView Answer on Stackoverflow
Solution 20 - JavaDeepak SelvakumarView Answer on Stackoverflow
Solution 21 - JavaPrakhar AdityaView Answer on Stackoverflow