Comparing Strings with Java

Introduction

In this tutorial, we'll be diving into String Comparison in Java.

String comparison is a common operation in all languages. The ability to check if one String is equal to another allows us to perform fundamental checks and alter the code flow.

The '==' Operator

The == operator is one of the first operators learned when diving into a new language, typically for comparing primitive data types like ints.

Let's take a look at how we can compare two String objects with the == operator:

String s1 = "Hello";
String s2 = "Hello";
String s3 = "World";

System.out.println(s1 == s2);
System.out.println(s2 == s3);

This would return:

true
false

This is expected - s1 == s2 and s2 != s3. However, let's rewrite this a bit into:

String s1 = "Hello";
String s2 = new String("Hello");

System.out.println(s1 == s2);

This returns:

false

This is because the == operator doesn't check for equality. It checks for identity.

In other words, it doesn't compares the Strings value - it compares object references.

The s1 is a reference variable to the same object in memory that s2 references. This is because the String Pool doesn't create new objects if we try instantiating a String with an already existing value.

However, when we instantiate s2 with the new keyword, we explicitly tell the JVM that we want a new object. Then, even though they have the same String value - the s1 and s2 reference variables refer to different objects, and thus the == operator returns false.

equals() Method

The equals() method is typically the way to go when comparing the contents of Strings. It's case sensitive and compares each character of the String to each character of the other String:

String s1 = "Hello";
String s2 = new String("Hello");

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

This will always return:

true

Whether we wrote s1.equals(s2) or s2.equals(s1), the result would be the same.

equals() is null-safe, which means it checks for null values for you. If we compare a non-null value to a null value, logically, the result is false:

String s1 = "Hello";
String s2 = null;

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

equalsIgnoreCase() Method

Since equals() is case-sensitive, in cases like Hello and hello, it'll return false. These truly aren't equal if case is important. However, in some situations, the case really isn't important. You'd just like to check if the characters themselves are the same, regardless of case.

For that, we use the equalsIgnoreCase() method:

String s1 = "Hello";
String s2 = "hello";

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

This results in:

false
true

compareTo() Method

The compareTo() method works in a different fashion from the equals() method. The compareTo() method checks for the String's lexigographical value.

If we compare s1 to s2 - if s1's lexigographical value is higher than s2's, the method will return a positive value. If it's lower, the method will return a negative value. If they're the same, the method will return 0.

This method is very useful if you'd want to sort words in a lexicographical order:

String s1 = "a";
String s2 = "b";

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

This returns:

-1

Since the difference in Unicode values for a and b is just 1. Let's take a look at another example:

String s1 = "Hello World";
String s2 = "hello world";

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

This results in:

-32

compareToIgnoreCase() Method

Similarly, there's a version of this method that doesn't care about the case of the characters. For example, the previous two Strings:

String s1 = "Hello World";
String s2 = "hello world";

System.out.println(s1.compareToIgnoreCase(s2));

Would now return:

0

contentEquals() Method

The contentEquals() is a relatively rarely used method, since it looks like it's the same as the equals() method.

Namely, the equals() method compares objects for equality. The String class overrides the default behavior to make it compare the contents.

The contentEquals() method compares CharSequences and StringBuffers. With it, you don't have to convert a StringBuffer into a String for comparison - the method will deal with that itself:

String s1 = "aaaa";
StringBuffer s2 = new StringBuffer("");

for (int i = 0; i < 4; i++) {
    s2.append('a');
}

System.out.println(s1.contentEquals(s2));

With the method from before, you can't compare a String to a StringBuffer. This way, you can.

This code returns:

true

StringUtils - Apache Commons

The Apache Commons library is a robust library filled with countless convenience methods and classes.

StringUtils is a helper class with a bunch of String-related operations, including the ones for checking equality.

StringUtils.equals()

The equals() method of the StringUtils class works in the same way we'd expect it to based on our familiarity with the Object.equals() method:

String s1 = "Hello";
String s2 = new String("Hello");

System.out.println(StringUtils.equals(s1, s2));
System.out.println(StringUtils.equals(s1, null));
System.out.println(StringUtils.equals(null, null));

This would return:

true
false
true

It also features null-safety and checks for null values. Comparing two null values will return true.

StringUtils.equalsIgnoreCase()

The equalsIgnoreCase() method works in the same fashion:

String s1 = "Hello";
String s2 = new String("hello");

System.out.println(StringUtils.equalsIgnoreCase(s1, s2));
System.out.println(StringUtils.equalsIgnoreCase(s1, null));
System.out.println(StringUtils.equalsIgnoreCase(null, null));

This returns:

true
false
true

StringUtils.equalsAny()

The equalsAny() is the first method that does something completely new. It accepts a String and a CharSequence vararg. If any of the varargs can be found in the String, it returns true:

System.out.println(StringUtils.equalsAny("Hello World", "Hello", "World"));
System.out.println(StringUtils.equalsAny("Java is great!", "Java", "great!"));

This would return:

true
true

Note: The method is case-sensitive.

StringUtils.equalsAnyIgnoreCase()

Of course, we also have a case-insensitive variant of the method:

System.out.println(StringUtils.equalsAnyIgnoreCase("Hello World", "HELLO", "world"));
System.out.println(StringUtils.equalsAnyIgnoreCase("Java is great!", "JavA", "GrEat!"));

These would also return:

true
true

StringUtils.compare()

The compare() method of the StringUtils class works in the same way as the compareTo() method of the String class. However, this convenience method is null-safe unlike the official implementation.

It follows the idea of a null value being lexicographically smaller than a non-null value, which makes a lot of sense.

String s1 = "a";
String s2 = "b";

System.out.println(StringUtils.compare(s1, s2));

This returns:

-1

StringUtils.compareIgnoreCase()

Finally, the case-insensitive version of the previous method - compareIgnoreCase(). It compares the lexicographical value of Strings, without taking the case into consideration:

String s1 = "A";
String s2 = "a";

System.out.println(StringUtils.compareIgnoreCase(s1, s2));

This would normally return -32 since lower-case letters are separated from their upper-case counterparts by 32 places. However, this returns:

0

Conclusion

String comparison in Java, as in other languages, is a common task. There's quite a few ways to go about it, both using built-in methods and the Apache Commons library.