Q: What's the difference between equals() and the == equality operator?
Short answer: In general, equals() checks for equivalence or logical equality between two objects. The == equality operator checks for primitive value equality as well as object reference equality. Avoid using (as in never, ever) == to compare boolean literals.
This question almost always comes up with respect to comparing Strings. Therefore, we will use Strings in most of the examples here.
This is the typical type of question many beginners ask:
Confused Beginner wrote:Why doesn't this code work?
Listing 1. Incorrect use of ==
== checks for reference equality
The first thing you should note is that a String is a full-blown object. Because Strings are objects, the variable response declared on line 2 is also called an object reference. That is, it references or points to a String object. When it is assigned a value, such as what happens when the call to input.next() succeeds, the response variable will reference or point to a String object that is made up of all the characters that the Scanner object, input, read.
String literals are also objects. The literal value "quit" on line 4 is a String object. The String object created on line 2 and referenced by the response variable is different from the String literal object "quit". So, when you use the == operator to compare response with "quit", you will get false because they are two different objects even when response refers to a String that is equivalent to "quit".
Here's another example that demonstrates how == works when used with objects.
Listing 2. How == works with object references
Lines 1 and 2 above create two new instances of Object and assigns each to the reference variables a and b, respectively. In line 3, the third reference variable, c, is simply assigned the same value as the variable a. Since a and b refer to two different objects, line 5 will print "false". Since a and c refer to the same object, however, line 6 will print "true". This is why when it comes to comparing object references, we say that the == equality operator checks for reference equality. That is, == checks if two object references point to the same object in memory.
equals() checks for object equivalence
To make the code in Listing 1 work, you need to use the equals() method instead. The equals() method of the String class checks for equivalence between two String objects. This code will work as expected:
Listing 3. Correct way to check equality of two objects, using equals()
You may think that the expression on line 4 is backwards, that it should be response.equals("quit") instead. That would actually work, too, and that's what many programmers will typically write. However, it's generally safer to call equals() on a String literal object when you are comparing it to a reference variable rather the other way around. We'll explain that part in a bit but right now, focus on the fact that using equals() works because we are checking for equivalence of two String objects instead of checking whether they reference the same object as what was happening when we used the == operator.
Specifically checking for reference equality with ==
We've already said that you should only use == if you want to specifically check for reference equality. What situations warrant such use? Ironically, one of the most common situations is when you override Object.equals(). One of the first checks you would perform when overriding equals() is whether the other object is in fact the current object. That is, equals() will always return true if you compare an object to itself. This is formally called the reflexive property of equals(): for any non-null reference value of x, x.equals(x) should return true. Listing 4 illustrates how a reference equality check with == is typically the first check in an equals() implementation.
Listing 4. Specifically checking for reference equality with ==
If you want to check whether two String objects contain the same sequence of characters, use the equals() method rather than the == equality operator.
In general, use equals() to check if two objects are logically equivalent to each other. Use == with objects only if you want to specifically check if they refer to the same thing in memory.
Note #1: Avoiding NullPointerException
As noted above about line 4 in Listing 3, it's safer to call equals() on a String literal if you are checking it against an object reference. It's possible to write line 4 as shown because the String literal "quit" is itself a String object and therefore it is legal to call String methods like equals() and length() on it. However, unlike a reference variable like response, a String literal can obviously never be null. The following code will produce a NullPointerException if somehow the object reference response is null.
Listing 5. Can potentially throw a NullPointerException
To safeguard against the possibility of response being null and getting a NullPointerException, you can add an extra check as shown below.
Listing 6. Checking for null first to safeguard against NullPointerException
This works because we're using the && operator which will short-circuit and skip the rest of the boolean expression if response is null, thus avoiding a NullPointerException. While this certainly works, writing it the way we did in Listing 3 instead is a shorter and more elegant way of avoiding a NullPointerException. When passed null, equals() is guaranteed to return false because a valid object reference can never be equal to null.
Note #2: Avoid using == (as in never, ever) with boolean literals
The following is poor form and should always be avoided:
Listing 7. Poor form: comparing boolean values with ==
The expression on line 3 above is redundant because (true == true) will always be true and (false == true) will always be false. Therefore, that code should be written as shown below in Listing 8 instead.
Listing 8. The proper way to use a boolean value in a conditional expression
Another reason you should avoid using == with a boolean literal is that it's easy to write = instead, as shown below in Listing 9.
Listing 9. A common bug: accidentally using =
There is a subtle bug on line 3 above that is often very easy to miss. The expression will always evaluate to true even if the variable processing is set to false inside the loop. This is because = is an assignment operation. So, regardless of what it's value is prior to evaluating the while loop condition on line 3, the assignment operation will override it to whatever value is assigned to the processing variable, which is true in this case. This results in the while loop never terminating as you would otherwise expect it to.
The same principle applies to the conditional expression of if-statements. The body of the if-statement shown below in Listing 10 will never be executed.
Listing 10. Bug: this kind of code will never be safe
Other Caveats and Gotchas regarding equals() and the == equality operator
To complicate things as explained above, there are specific cases when equals() and == will give the same result. Don't allow the behavior in these special cases to mislead you into ignoring the general advice you were given above.
Special case #1: Object.equals() checks for reference equality.
The primordial java.lang.Object class itself has a very basic implementation of equals(): it just checks for reference equality. Because of this, subclasses like String override the equals() method so they can change the default behavior that is inherited from Object.equals() and provide a more logical equivalence check. So, when comparing two references to Object or any class that does not override Object.equals(), you will get the same result as you would if you used == instead. However, you should still avoid writing code that relies on this behavior, especially when you are using references to subclasses whose implementation of equals() could still be overridden at some point in the future. Again, when you are dealing with object references, always use equals() unless you want to check for reference equality specifically.
Special case #2: Enum types and certain constants
The Java Tutorials define enum types as "a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it." Since the enum values are predefined constants, they are guaranteed to be unique values and as such there will only be one instance of each value in memory at any given time. Therefore, it is fine to use either == or equals() to compare enum references, even if they are technically object references.
In the same vein as enum types, it should also be safe to use == to check references to a true Singleton instance. It would be prudent to write unit tests that verify and document the behavior of == with respect to singleton instance references specifically.