Tuesday, September 3, 2024

5 ways to Compare String Objects in Java - Example Tutorial

here are many ways to compare String in Java e.g. you can use equals() and equalsIgnoreCase() for equality check and compare() and compareTo() for ordering comparison. You can even use the equality operator == to perform reference-based comparison e.g. to check both the String reference variable points to the same object. In general, equals() is used to check whether the value of a given String is the same i.e. they contain the same characters in the same sequence or not e.g. "Groovy".equals("Groovy") will be true if you compare them using equals() method. You can also use equalsIgnoreCase() to check if they are equal irrespective of case e.g. "Apple" and "apple" will be the same if you compare them using equalsIgnoreCase() method.

If you want to do lexicographic comparison e.g. to find out whether a String object comes before or after another String object then you can use the compareTo() and compare() method. The compareTo() method comes from java.lang.Comparable interface and you can use this to compare one String to another.

It will return negative if first string comes before second string in lexicographic order, positive if first string comes after second string, and zero if both strings are equal to each other. The compare() method allows you to compare String on any custom order, for example, you can use this to compare string on their length.

And, if you are interested in reference comparison, you can use the equality operator to see if two string reference variables point to the same object or not. This is not the right way to compare String in Java but if you really need the reference based comparison that's the way to go.

In this article, I'll go through each of the ways to show you how exactly you can compare String objects in Java.



String Comparision using equals() method

If you just want to check if two string is same i.e. they are of the same case, contains same characters and in the same sequence then you should use equals() method. 

This method is defined in java.lang.Object class for reference comparison but java.lang.String overrides this method to perform the value-based comparison. 

This method returns true if both objects are same and false if they are not same. If you compare a non-null String value to a null string then also it returns false.

Here is a couple of examples of using equals to compare String in Java:

// comparing string using equals() method
String primaryLanguage = "Java";
String secondaryLanguage = "Groovy";

// true because primaryLanguage points to "Java"
"Java".equals(primaryLanguage); 

 //false because one is Java, other is Groovy
"Java".equals(secondaryLanguage);

//false - same reason
primaryLanguage.equals(secondaryLanguage); 

// false - because comparing a non-null to null String 
primaryLanguage.equals(null); 

You can see that comparing a non-null string to a null string will also return false. You can see The Complete Java Master Class to learn more about essential Java concepts like equals in Java.



Comparing String using equalsIgnoreCase()

The equals() method does case-sensitive comparison e.g. "Apple" and "apple" will not be considered equal if you use equals() method but if you treat them same i.e. you perform case-insensitive comparison then you should use equalsIgnoreCase() method. This method comes from java.lang.String class and hence you can it on both string literals and string objects.

Here is a couple of examples of comparing String using equalsIgnoreCase() method:

// comparing string using equalsIgnoreCase() method
String camelcase = "Java";
String capitalcase = "JAVA";
String smallcase = "java";

"Java".equalsIgnoreCase(camelcase); // true 
"Java".equalsIgnoreCase(smallcase); //true
camelcase.equalsIgnoreCase(smallcase); //true
capitalcase.equalsIgnoreCase(smallcase); //true

"Groovy".equalsIgnoreCase(camelcase); //false, Groovy and Java is not equal

You can see that equalsIgnoreCase() return true even if you compare String in camel case, small case, and in capital letters.

5 ways to Compare String Objects in Java


String Comparision using compareTo()

The compareTo() method is used to compare String on alphabetic or alphanumeric order, precisely known as a lexicographical order. The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argument string.

It returns a negative integer if this String object lexicographically precedes the argument string and a positive integer if this String object lexicographically follows the argument string. The result is zero if both strings are equal.

It's also worth noting that compareTo() should return zero if two objects are equal using the equals() method and you should follow this contact while overriding compareTo() in Java. Failing to do may return unexpected behavior when you store these objects in the Collection classes which uses both equals() and compareTo() e.g. HashSet.

Here is a couple of examples of comparing strings using the compareTo() method in Java:

// comparing string using compareTo() method
String java = "Java";
String groovy= "Groovy";

// positive integer because java comes after groovy in alphabetic order
int result = java.compareTo(groovy); 

// negative integer because groovy comes before java in alphabetic order
result = groovy.compareTo(java); 

// zero because both "Java" and string referred by java reference variable
// is same
result = "Java".compareTo(java);

You can see that compareTo() compares String in their natural order, for string its alphabetic or lexicographic order. That's why when you compare "Java" to "Groovy" you get the positive integer and if you reverse order you get negative integer because "Java" comes after "Groovy" in alphabetic order. See The Complete Java Developer Course to learn more about how to correctly implement the compareTo method in Java.




String Comparision using compare() method

The compare() method, which comes from Comparator provides you the luxury to compare String in any custom order. One of the common applications of this is comparing strings by their length. All you need to write an implementation of compare() method which compares given String by their length as shown below. You can this code to sort a list of String by their length as shown here.

Comparator<String> compareStringByLength = new Comparator<String>() {

  public int compare(String first, String second){
    return first.length() - second.length();
  }
};

String shorter = "ABCDEFG";
String longer = "ABCDEFFSGSFSDS";

 // negative integer because shorter's length less than longer
int result = compareStringByLength.compare(shorter, longer);

 // positive integer - length of first string is greater than second
result = compareStringByLength.compare(longer, shorter);

 //zero - length of both first and second string is same
result = compareStringByLength.compare(shorter, shorter);

You can see that when we compare shorter with longer, we get a negative integer because the length of the shorter string is less than the longer one. Similarly, we get the positive integer when we reversed the order and zero when we compare the string by itself.

The flexibility provided by the compare() method is very useful if you want to order a list of string in any custom order e.g. by their length.

Btw, from Java 8 onwards, you can use lambda expression and method reference while creating Comparator in Java, which means the whole code to implement compare will fit on one line as shown below:

Comparator<String> compareStringByLength = (String s1, String s2) 
                                                   -> s1.length() - s2.length();

You can see that all the boilerplate code is gone and only the code which matters is remaining. The Java compiler also does a lot of Type inference which means you can further shorten the code by removing String from the right-hand side of the code as shown below:
Comparator<String> compareStringByLength = (s1, s2) 
                                                   -> s1.length() - s2.length();

In short, from JDK 8 onwards, always use lambda expression while implementing compare() method in Java. See Java 8 - Beyond the Basics to learn more about new features of Java SE 8 release.



String Comparision using == (equality) operator

Some of you might be thinking why I have kept this as a last option for comparing strings in Java? Well, I did it on purpose because I want to discourage Java developers from using the == operator for comparing String.

It's not meant for String comparison because it checks if two string variables pointing to the same object or not. That's not what you want in most cases. Many Java beginners use == operator thinking that it compares values and in the process creates subtle bugs unknowingly.

It may seem to work for many inputs because Java internally uses a String pool to cache String literals but it will not work as expected i.e. it may return false if two string has the same value but they are different objects, which can be very hard to guess and troubleshoot sometimes.

Here is a couple of examples of comparing strings using == or equality operator in Java:

String literal = "Java";
String anObject = new String("Java");

// true because both literal and "Java" points to same String object in 
String pool
boolean result = (literal == "Java"); 

// false because of both point to different string objects. 
result = literal == anObject; 

You can see that it return true in the first case because both "Java" and literal reference variable points to the same String object in the String pool but false when you compared literally with anObject, even if they contain the same String value.

That's why it's very dangerous to use == operator for comparing String in Java. You should always avoid this method unless you know what you are doing.

Things get even more complex when you use intern() method, for example, what does following comparison will return, true or false?

String literal = "Java";
String anObject = new String("Java");
String fromPool = anObject.intern();

boolean result = literal == fromPool; // true or false?

This will return true because intern() method returns the equivalent object from the String pool, hence anObject.intern() will return the reference to the same object pointed by literal reference variable. You can learn more about that in my post how the intern() method works in Java.




Important Points

Now that you know multiple ways to perform String comparison in Java, let me share you some important points and useful tips and trick you can follow while comparing strings in Java.

1) Whenever you use the equals() and equalsIgnoreCase() method to compare a String literal e.g. "Groovy" to a String object, you should always call equals() on string literal e.g. "Groovy".equals(mayBeGroovy). This will help you to avoid NullPointerException when mayBeGroovy is null.

If you reverse the order then also the code will work for non-null values of the mayBeGroovy object but will throw NullPointerException when mayBeGroovy is null. This is also one of the common tips to avoid NullPointerException in Java.

2) Always use equals() if you are checking for equality because it does a value-based comparison.

3) Use equalsIgnoreCase() for case-insensitive equality check.

4) Don't use == to compare String in Java. It performs reference equality check and only returns true if both String point to the same object. This means even if the content of two String is same == may return false if they point to different objects.

The use of == for comparing string creates subtle bugs because of String pool. It may return true for some inputs mostly when you compare String literals to string objects, making you believe that its working fine, but it won't work if two reference variable point to two different objects which contains exactly same content i.e. same characters in the same case and in the same sequence. See the difference between equals and == in Java for more details.

5) Use compareTo() for alphabetic comparison for String objects. When you override compareTo() method, make sure that it follows its contract with equals() method i.e it should return zero when two objects are equal with equals() method.

You can also see here to learn more about equals() and compareTo() relationship and impact of not following the specified contract.

6) Use compare() to perform any customize comparison e.g. if you want to compare Strings by their length. Also, from JDK 8 onwards, always use a lambda expression in place of anonymous class while creating Comparator in Java as shown in complete Java SE 8 developer BootCamp.


That's all about different ways to compare String objects in Java. As a rule of thumb, you should always use equals() to compare String in Java, if you only want to check if given String are same or not, but you should remember that equals() are case-sensitive. If you want to ignore case, better use equalsIgnoreCase().

You can use compareTo() and compare() if you are interested in the relative ordering of string objects e.g. while sorting strings in the list. You should never compare string using == unless you know what you are doing i.e. you purposefully checking if two string points to the same object.

Other Java and String tutorials you may like:
How to join String in Java 8? 
How to split a comma-separated String in Java?
How to replace characters and substring in a given String?
3 ways to convert JSON String to Java Object?

Thanks for reading this article so far. If you like this article and my explanation then please share with your friends and colleagues. If you have any questions or feedback then please drop a note.

No comments:

Post a Comment

Feel free to comment, ask questions if you have any doubt.