How to correctly compare Strings (and objects) in Java?

67

I am creating a mini game in which the user tries to guess a name. But when I want to compare two text strings to see if they are equal it does not 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!");
    }
}

DEPARTURE:

Adivina mi nombre: 
manuel
Intentalo de nuevo!
jordi
Intentalo de nuevo!
Jordi
Intentalo de nuevo!
    
asked by Jordi Castilla 02.12.2015 в 13:35
source

12 answers

95

In Java only the primitive types (Described in the JLS (§4.2) , for example int or char ) are compared with == , String s (and other objects) in Java are compared to each other with the method equals .

String#equals(Object)

  

Compare this String with the specified object. The result is true if, and only if the argument is not null and is an object of type String that represents the same sequence of characters as this object.

  • JLS (§15.21.3) Yes you can use == to compare references of type String , an equality test determines whether the two operands refer to the same object String . The result is false if the operands are different String objects, even if they contain the same sequence of characters.

Therefore your comparison should be:

if(miNombre.equals(intento)) {

DEPARTURE:

Adivina mi nombre: 
manuel
Intentalo de nuevo!
Jordi
Acertaste!

CLARIFICATIONS:

  • I have set the variable miNombre at the beginning of the comparison to avoid a NullPointerException if intento == null (yes, comparisons with null are also made with == ).

    As an extra: if null is a valid value in the representation (and therefore we want to avoid a NPE ), Objects.equals is available from Java 7 and is responsible for returning true if both are null or false if only it is one.

  • In this case you can use the method String#equalsIgnoreCase(Object) that you will ignore MAYUSCULAS or MINUSCULAS when doing the comparison:

    if(miNombre.equalsIgnoreCase(intento)) {       
    
  • 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 type boolean or Boolean or two operands that > are of reference type or type null . All other cases cause a compile-time error.

answered by 02.12.2015 / 13:35
source
27

From Java 7 it is possible to compare the equality of two strings using the method equals of the class java.util.Objects . This is:

String a = ...
String b = ...

if (Objects.equals(a, b)) {
    // iguales
} else {
    // diferentes
}

Since a.equals(b) or b.equals(a) can throw java.lang.NullPointerException if a is null or b is null respectively, when using this path, a or b can be null without any risk.

If you are using Java 6 (or smaller), starting with the code in this class, we can rewrite our if of the next way:

if (a == b || (a != null && a.equals(b))) {
    // iguales
} else {
    // diferentes
}
    
answered by 03.12.2015 в 04:05
17
  • The "==" operator compares two references, that is, returns true if both objects occupy the same memory location.

  • The "equals" method compares the values of the objects.

answered by 09.12.2015 в 12:27
13
  

The Java function is used in the language equals() to compare    strings , NEVER use the operator == .

String nombre = "elenasys";

if (nombre.equals("elenasys")) { //Correcto para comparar strings!
    ...
}

if (nombre == "elenasys") {   //Incorrecto para comparar strings!
    ...
}

This is a common mistake in new developers.

    
answered by 02.12.2015 в 17:06
8

As already mentioned, the operator == verify in the case of primitives that the values are identical, in case of objects that the reference points to the same object.

A little explanation of the equals () method is still needed All classes in Java are subclasses of Object , object comes with a default declaration of equals () .

If I declare a new class, other users in my class expect me to implement an equals (Object or) method that implies that two objects are considered equal. That does not necessarily mean they are, and may require comments in the documentation. An example:

public class Point(){
    private int x;
    private int y;

    public Point(intx, int y){
        this.x=x;
        this.y=y;
    }

    public int getX() {return x;}

    public int getY() {return x;}

    @Override
    public boolean equals(Object o){
        return o instanceof Point && ((Point)o).getX()==x && ((Point)o).getY()==y;
    }
}

If I declare a subclass of Point with a label like:

public class NamedPoint extends Point{

    private String etiqueta;

    public NamedPoint(int x, int y, String etiqueta){
        super(x,y);
        this.etiqueta=etiqueta;
    }

    public String getEtiqueta(){ return etiqueta }
}

should comment that two NamedPoint are considered equal if the coordinates correspond, regardless of the tag.

Eye, simply overwriting the method does not ensure consistency in my logic. If I overwrite equals in NamedPoint to also consider the tags, I'm left with the following problem:

Point point = new Point(3,6);
Point otroPoint = new NamedPoint(3,6,"Foo");
boolean equals1 = point.equals(otroPoint); // resultado true
boolean equals2 = otroPoint.equals(point); // resultado false

to escape this ambiguity you can compare classes instead of using instanceof:

    @Override
    public boolean equals(Object o){
        return this.getClass().equals(o.getClass()) 
            && ((Point)o).getX()==x && ((Point)o).getY()==y;
    }

Summary: there are dragons on the subject of equality.

    
answered by 08.01.2017 в 08:31
8

To complement the other answers I will tell you that there is no rule to compare the equality of a chain, both the method .equals() and the operator == are fully valid, the difference depends on what you want to compare or what is really your intention when wanting to compare two objects String , (by reference or by value).

Chains are Objects like any other but there are great and subtle differences that separate them from the rest of Objects, first of all you can initialize a chain in these two ways.

String usandoLiteral = "Mi literal"; // Por medio de un literal
String usandoNew = new String("Con operador new"); // Utilizando el operador clasico new

In both cases an object is being created, the absence of the operator new in the first example is only a shortcut (so it looks more natural).

Now we have to understand how Java manages the strings, in Java there is the String Pool, this is a memory space reserved for storing the strings, an application usually makes a strong use of Strings and only these can occupy up to a 40% of the memory in runtime and many of these String's are repeated for example 'a' 'in' 'the' 'etc. To optimize this, Java collects all these strings as literals in a JVM location and reuses repeated literals to optimize the use of memory, 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 that you are creating two Objects)

String nombre = "carlos";
String nombre2 = "carlos";

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.

Boolean sonIguales = nombre == nombre2; // sonIguales tiene el valor true

The String Pool only recycles and stores literals, this means that if you create a string in the following way

String nombre3 = new String("carlos");

Not being initialized with a literal java will not store it in the String Pool nor will there be recycling therefore it will be eliminated by the Garbage Collector, if this is so then the following comparison will result in false.

Boolean esIgualAlTercero = nombre == nombre3; // esIgualAlTercero tiene el valor false.

This is the reason why when you make the comparison with the operator == sometimes it will give you true and sometimes it will give you false even though you compare the same value in the chain.

The .equals method you use when you want to compare the string by value or character by character, is a sure way to make the string comparison since remember that as in the first example we technically made a comparison by value with the operator = = due to the peculiarity of the String Pool.

An additional note in case you ask, if initializing a string by literal value is stored in the String Pool that happens when I change the string?

Well that's another point, the chains in Java are immutable, this means that you can not modify their value for example adding more characters to a String value and Java does not provide any API to modify a String directly. (however, Java provides an API 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 to the variable (name) a new string that I'll build it by concatenating the original value with the last name of this way.

nombre = nombre + " lucero"; 

This what it does is create a new value "carlos lucero" and assign this value to the string name.

Now what happens if I now compare 'name' with a new variable that contains the same value as 'name' but assigned as literal?

String nombreCompleto = "carlos lucero";
Boolean esNombreCompletoIgual = nombreCompleto == nombre; // recuerda que nombre ahora tiene el valor "carlos lucero"

Because the variable (name) was re assigned to a new value that was not created by means of a literal because now the variable (name) is no longer in the String Pool, therefore your reference is not recycled and the comparison with the variable (fullName) that was created by means of a literal will result in False.

Finally Java provides an API to solve the problem of immutability of the chains, this API is exposed by the class StringBuilder .

    
answered by 29.12.2016 в 21:45
7

The == operator usually works when the variable has already been initialized, since it compares the internal representations, but the most correct thing to do is compare using the equals method that is inherited from the class Object .

Comparing them with equals is almost always the best solution

String cadena1="Hola";
String cadena2="Hola";
System.out.println(cadena1.equals(cadena2)); //funciona

String cadena1;
String cadena2="Hola";
System.out.println(cadena1.equals(cadena2)); //funciona

But in spite of this you could have problems if your virtual machine is smaller than the Tiger, because in misleading implementations a chain defined as null was not the same as an empty string.

String cadena1="";
String cadena2=null;
String cadena3;
System.out.println(cadena1.equals(cadena2).equals(cadena3));

So for those cases you can use the comparison using the operator ==

String cadena1="Hola";
String cadena2="Hola";
System.out.println(cadena1 == cadena2); //funciona porque ya están inicializadas

Or having a lot of reservation, comparing the internal representations.

String cadena1="Hola";
String cadena2="Hola";
System.out.println(cadena1.intern() == cadena2.intern()); //son iguales solamente si cadena1.equals(cadena2)
    
answered by 03.12.2015 в 16:46
7

"==" is used for an Integer, Char, Object, or null, among others, better use equals or equalsIgnoreCase:

 final String miNombre = "Jordi";
Scanner input = new Scanner(System.in);
System.out.println("Adivina mi nombre: ");

while (true) {
    String intento = input.next();
    if(intento.equalsIgnoreCase(miNombre)) { //Tu puedes usar equals para que sea igual y equalsIgnoreCase para que se igual ignorando las mayúsculas && minúsculas, es decir que por mas que escribas JoRdI va a ser "true".
        System.out.println("Acertaste!");
        break;
    } else {
        System.out.println("Intentalo de nuevo!");
    }
}
    
answered by 20.08.2016 в 06:16
6

The correct way to compare 2 Strings is by using the equals () , which is to compare the 2 strings and equalsIngnoreCase () which is the same but ignoring the uppercase and lowercase.

Try with:

if(intento.equalsIgnoreCase(miNombre)){
     System.out.println("Has Acertado");
}
else{
     System.out.println("Incorrecto");
}
    
answered by 16.10.2016 в 00:06
6

Only for primitive types the comparison == is valid in general. For objects, you must use comparison methods such as equals() that might be valid for Strings . For other types of objects, this type of comparison may not be valid.

With == references are compared and not content of the objects in memory.

    
answered by 15.10.2016 в 21:51
4

In java the correct way to compare Strings is by using the equals method which is inherited from the Object class

example:

String str1 = "hola"
String str2 = new String("hola");
String str3 = "hola";
System.out.println(str1 == str2); //falso 
System.out.println(str1 == str3); //verdadero
System.out.println(str1.equals(str2)); //verdadero
System.out.println(str2.equals(str3)); //verdadero

When declaring a String like this: String str="string"; the object is a literal (declared value at the time of writing the code) and is stored in the String pool (pool where the chains are stored only once and are read several times by literals)

so:

"cadena" es distinto a new String("cadena") ;

since the latter is generated at run time and is not in the String pool.

    
answered by 08.03.2017 в 16:17
1

You can implement the String.equals ("") method; that the same Java API brings as well as you must implement the corresponding validations such as: perform the string.trim (); to the text that you want to validate since a space also counts at the time of comparison. this method is to remove the spaces at the end and at the beginning of the chain. You can also include string.lengt (); to perform your validations everything depends on your needs. regards Simple example:

String micadena="Hola mundo";
String cadenaGuardada="Hola mundo";

if(micadena.equals(cadenaGuardada))
return "iguales";
else
return "No son iguales";
    
answered by 13.09.2017 в 21:14