I am creating a mini game where the user tries to guess a name. But when I want to compare two text strings to see if they are the same it doesn't seem to work.
final String miNombre = "Jordi";
Scanner input = new Scanner(System.in);
System.out.println("Adivina mi nombre: ");
while (true) {
String intento = input.next();
if(intento == miNombre) {
System.out.println("Acertaste!");
break;
} else {
System.out.println("Intentalo de nuevo!");
}
}
EXIT:
Adivina mi nombre:
manuel
Intentalo de nuevo!
jordi
Intentalo de nuevo!
Jordi
Intentalo de nuevo!
Where
Java
only primitive types (Described in the JLS (§4.2) , for exampleint
orchar
) are compared with==
, theString
s (and other objects) inJava
are compared with each other with the methodequals
.String#equals(Object)
==
to compare type referencesString
, an equality test determines whether the two operands refer to the same objectString
. The result isfalse
if the operands are different String objects, even if they contain the same sequence of characters.So your comparison should be:
EXIT:
CLARIFICATIONS:
I have put the variable
miNombre
at the beginning of the comparison to avoid anNullPointerException
ifintento == null
(yes, comparisons withnull
are also made with==
).As an extra: if it
null
is a valid value in the representation (and therefore we want to avoid aNPE
), itObjects.equals
is available fromJava 7
and takes care of returning true if both are truenull
orfalse
if only one is true.In this case you can use the method
String#equalsIgnoreCase(Object)
that will ignoreMAYUSCULAS
orMINUSCULAS
when doing the comparison:JLS (§15.21) The equality operators (
==
and!=
) can be used to compare two operands that are convertible (§5.1.8) of numeric type, or the two operands of typeboolean
or ,Boolean
or two operands that>
are of type reference, or the typenull
. All other cases cause a compile-time error.Since Java 7 it is possible to compare the equality of two strings using the method
equals
of the classjava.util.Objects
. That is:Since they can
a.equals(b)
eitherb.equals(a)
castjava.lang.NullPointerException
if ita
isnull
orb
it isnull
respectively, when using this path,a
orb
they can benull
without any risk.If you're using Java 6 (or lower), from the code in this class, we can rewrite our
if
as follows:The "==" operator compares two references, that is, it returns true if both objects occupy the same memory location.
The "equals" method compares the values of the objects.
This is a common mistake for new developers.
To complement the other answers I will tell you that there is no rule to compare the equality of a string, both the method
.equals()
and the == operator are totally valid, the difference depends on what you want to compare or what your intention is when you want to compare two objectsString
, (by reference or by value).Strings are Objects like any other but there are big and subtle differences that separate it from the rest of Objects, first of all you can initialize a string in these two ways.
In both cases an object is being created, the absence of the operator
new
in the first example is just a shortcut (so it looks more natural).Now you have to understand how Java manages strings, in Java there is a String Pool, this is a memory space reserved for storing strings, an application normally makes heavy use of Strings and only these can occupy up to 40% of the memory at runtime and many of these String's are repeated eg 'a' 'en' 'la' etc. To optimize this, Java collects all these strings as literals in a JVM location and reuses the repeated literals to optimize memory usage, so if you store the literal "carlos" in two variables, Java will reuse this literal.
For this reason if you declare the following variables
String
and initialize them with the same literal. (remember you are creating two Objects)The comparison with the == operator will return true, because the String Pool recycles the literal "carlos" and therefore they are the same reference, therefore it is completely valid to make the comparison.
The String Pool only recycles and stores literals, this means that if you create a string as follows
As it is not initialized with a java literal, it will not be stored in the String Pool nor will there be recycling, therefore it will be eliminated by the Garbage Collector, if this is the case then the following comparison will result in false.
This is why when you do the comparison with the == operator it will sometimes return true and sometimes return false even though you are comparing the same value in the string.
The .equals method is used when you want to compare the string by value or character by character, it is a safe way to do the string comparison since remember that as in the first example we technically did a comparison by value with the == operator due to the peculiarity of the String Pool.
An additional note in case you are wondering, if when initializing a string by literal the value is stored in the String Pool, what happens when I modify the string?
Well that's another point, strings in Java are immutable, this means you can't modify their value, for example add more characters to a String value and Java doesn't provide any API to modify a String directly. (however Java provides an API to be able to do it indirectly)
For example, if I want to add the last name to my variable (name), what I can do is re-assign a new string to the variable (name), which I will build by concatenating the original value with the last name in this way.
What this does is create a new value "carlos lucero" and assign this value to the name string.
Now what happens if I now compare 'name' with a new variable that contains the same value as 'name' but is assigned as a literal?
Well, since the variable (name) was re-assigned to a new value that was not created by means of a literal , now the variable (name) is no longer in the String Pool, therefore its reference is not recycled and the comparison with the variable (FullName) that if it was created by means of a literal will give False as a result.
Finally, Java provides an API to solve the string immutability problem, this API is exposed by the class
StringBuilder
.As already mentioned, the == operator confirms in the case of primitives that the values are identical, in the case of objects that the reference points to the same object.
It remains to explain a bit about the equals() method. All classes in Java are subclasses of Object , object comes with a default declaration of equals() .
If I declare a new class, other users of my class expect me to implement an equals(Object o) method which implies that two objects are considered equal. That doesn't necessarily mean they are, and may require comments in the documentation. An example:
If I declare a subclass of Point with label like:
I should comment that two NamedPoints are considered equal if the coordinates match, regardless of the label.
Beware, simply overriding the method does not ensure consistency in my logic. If I override equals in NamedPoint to also consider the labels, I am left with the following problem:
To escape this ambiguity you can compare the classes instead of using instanceof:
Summary: There are dragons on the issue of equality.
The == operator usually works when the variable has already been initialized, since it compares the internal representations, but the most correct method is to compare using the equals method that is inherited from the class
Object
.Comparing them using equals is almost always the best solution
But despite this you could have problems if your virtual machine is smaller than Tiger, because in unfortunate implementations a string defined as
null
was not the same as an empty string.So for those cases you can use the comparison using the operator
==
Or having a lot of reserve, comparing internal representations.
"==" is used for an Integer , Char, Object, or null, among others, better use equals or equalsIgnoreCase:
Only for primitive types the comparison == is valid in general. For objects comparison methods should be used as
equals()
it could be valid forStrings
. For other types of objects this type of comparison might not be valid.With == references are compared and not the contents of the objects in memory.
The correct way to compare 2 Strings is by using the equals() function , which is to compare the 2 strings and equalsIngnoreCase() which is the same but ignoring case.
Test: