Pavle Jonoski
By Pavle Jonoski

Java String.equals vs '=='

Java String.equals vs '=='

Java String equals vs the (==) equality operator

TL;DR; Always use String.equals or Objects.equals on strings. == compares

memory locations, not the actual content of the string. This is important as

string literals are not kept in the heap and different string objects on the

heap will have different memory locations even if they have the same content.

Java is a bit weird when it comes to string comparison. I remember me getting

stumped when I first needed to compare strings in Java. I used the == comparison

operator and got some weird results that I didn’t expect, for example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if("foo" == "foo") {

    // This always gets through

}



// However this

if(myVariable == "foo") {

    // would sometimes works, but other times will not work.

}

So what is going on?

It all stems from the way Java handles variables and constants in your code.

Maybe you’ve heard of string literals. Literals in Java are primitive data types (like int,

float, boolean and sometimes String) which are not instantiated using the new keyword, like these

int i = 10; or String str = "foo";. Notice that there is no new keyword before any of these.

When defined like this, Java considers these values as constants and keeps them

in a special place in the jvm memory used for constants. The idea behind this is

a form of optimization - whenever Java encounters the same value in the code, it does

not allocate new memory on the heap, but instead will reuse the value that already

has in the static memory.

However, if we create new values using the new keyword, we’re instructing the

jvm to actually allocate new slot on the heap for our value: String str = new String("foo");.

By now you may have some idea of what is going on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String a = "foo";  // this is a literal and goes in the static memory

String b = "foo";  // also a literal, with same value as 'a', so 'b' points to the same

                   // memory location as 'a'



String c = new String("foo")  // We allocate "foo" on the heap, although it has the

                              // same value as 'a' and 'b', it is in a different

                              // memory location - namely on the heap

When doing == comparison in Java, by default the jvm compares memory locations - it will

compare whether the memory address of the two objects is the same, and if it is, then the

objects must be the same.

But the strings allocated with new will always get new locations on the Heap, and ==

will get two different memory locations and will evaluate to false.

The way around this is to use String.equals method.

This method compares the string content, and not the memory addresses. And that is what we want

when comparing strings.

Here is some weirdness and examples on how to compare string and what not to do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43


String a = "foo";

String b = "foo"; 



a == b  // -> true, but don't do this.



a.equals(b)  // true. Do this instead.



String a = "foo";

String b = new String("foo")



a == b  // false. One is a string literal, the other is a regular object on the heap.



a.equals(b) // true. Compares the content: "foo" is equal to "foo".





// Alternative approach, with Objects.equals

Objects.equals("foo", "foo")               // true

Objects.equals("foo", null)                // true. Protects us from null pointer dereferencing.

Objects.equals("foo", new String("foo"))   // true



So basically we want to use String.equals to compare the content of the strings. However

in some cases we may run into problems, namely in the cases when we try to call equals from

a variable that is null:

1
2
3
4
5
6
7
8
9
String a = null;



a.equals("foo");  // NullPointerException



So in cases when we’re comparing with a literal, always call equals from the literal:

1
2
3
4
5
6
7
String a = null;



"foo".equals(a)   // false. No exception was thrown.

Alternatively you can use Objects.equals (available from java 1.7).

This does what we want and takes care of the null values.

1
2
3
4
5
6
7
String a = null;



Objects.equals(a, "foo") // false. no exception thrown.