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.
Details
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 ==
Summary
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.
Additional Notes
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
See also:
Avoid the Equality Operator
When equals() and == give the same result
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.