How to compare Strings in Java?

51

The == operator says that the Strings are different, and they store the same literal value, see example:

public class TesteString {
    public static void main(String[] args) {

        String str1 = "teste";
        String str2 = "Oteste".substring(1);

        System.out.println("str1: " + str1 + ", str2: " + str2);
        if(str1 == str2) {
            System.out.println("str1 igual a str2");
        }
        else {
            System.out.println("str1 diferente de str2");
        }
    }
}

Result:

str1: teste, str2: teste
str1 diferente de str2

How do I compare the literal value of Strings?

    
asked by Math 03.02.2014 в 16:19

4 answers

41

Playing with == and with pool of Strings

Java uses a mechanism called String interning , placing the Strings in pool to try to store only one copy of each character sequence in memory.

When Java finds string literals in code, it always returns a same instance of String, which points to an inner JVM in the pool . Therefore, it is quite possible to use the == operator to compare two variables that receive String literals:

String literal = "str";
String outraLiteral = "str";

System.out.println(literal == outraLiteral); //exibe true

In addition, as Java treats String literals as instances it is possible to compare a literal directly, like this:

System.out.println(literal == "str"); //também retorna true

On the other hand, we can not trust the comparison operator when we do not know how the String was created, since it is possible to create other instances in several ways. Example:

String novaInstancia = new String("str");
System.out.println("str" == novaInstancia); //retorna false

The above code creates a new instance of String, which is not the same as that returned by the JVM for the literal "str" .

But, however, this does not mean that we have two entries of "str" in the pool of Java. How can we verify this? Using the String.intern() method, which returns a reference to the String that is in the pool . Example:

String novaInstancia = new String("str");
System.out.println("str" == novaInstancia.intern()); //retorna true

Applying this to the example question, we would have:

public class TesteString {
    public static void main(String[] args) {

        String str1 = "teste";
        String str2 = "Oteste".substring(1);

        System.out.println("str1: " + str1 + ", str2: " + str2);
        if(str1 == str2.intern()) {
            System.out.println("str1 igual a str2");
        }
        else {
            System.out.println("str1 diferente de str2");
        }
    }
}

And the result:

  

str1: test, str2: test

     

str1 equal to str2

All very interesting. But what if we were to create a String in a way that was amazing?

StringBuilder sb = new StringBuilder();
sb.append('s');
sb.append('t');
sb.append('r');
System.out.println("str" == sb.toString().intern()); //continua sendo true

But what about equals() ?

If the comparison with == is faster than the equals() method, should we abandon equals() and use intern() everywhere? The answer is no .

Not all Strings are internalized in pool immediately. When we call the intern() method, if it is not there, then Java will add it. The problem is that once in the pool the String goes to permanent memory and will no longer be collected by the garbage collector .

When you want speed and the set of values is relatively small, using the intern() method can be advantageous. But if we use this feature, for example, for processing text files, XML, databases, we will soon see OutOfMemoryError .

In addition, adding a Strings in pool can also be an "expensive" operation. In addition to checking to see if the String already exists, Java will probably have to handle competing accesses.

And finally, a big disadvantage is that the code gets more prone to bugs ( error prone ), since the developer must always put intern() when needed.

Other ways of comparison

Going just beyond the exact comparison of Strings, we have other interesting ways of comparing:

Case insensitive (not case sensitive)

System.out.println("STR".equalsIgnoreCase("str")); //retorna true

A string contained in another

System.out.println("###STR###".contains("STR")); //retorna true

Which string is "bigger" than the other?

System.out.println("str1".compareTo("str2")); //retorna -1, pois "str1" é menor que "str2"

Or:

System.out.println("str1".compareToIgnoreCase("STR2")); //retorna -1, ignorando a capitalização

The compareTo method returns:

  • 1 if the first String is greater than the second
  • 0 if they are equal
  • -1 if the first String is less than the second

Starts with ...

System.out.println("str1".startsWith("str")); //returna true, pois "str1" começa com "str"

Ends with ...

System.out.println("str1".endsWith("r1")); //return true, pois "str1" termina com "r1"

Regular expression

System.out.println("str2".matches("\w{3}\d")); //return true, pois corresponde à expressão regular

Is it empty?

String str1 = "";
System.out.println(str1.isEmpty());
System.out.println(str1.length() == 0);
System.out.println(str1.equals(""));

Particularly I prefer the first method for Java > = 6 and the second method for earlier versions.

    
03.02.2014 / 19:22
36

Variables of type String store object references, not a literal value of String. Then == compares the reference, and will only return true if both variables are referencing the same object.

.equals() is a method of class Object , which compares the values of the literals stored by objects, so this method must be used to compare values of the literal of variables of type String .

public class TesteString {
    public static void main(String[] args) {

        String str1 = "teste";
        String str2 = "Oteste".substring(1);

        System.out.println("str1: " + str1 + ", str2: " + str2);
        if(str1.equals(str2)) { //perceba a diferença aqui
            System.out.println("str1 igual a str2");
        }
        else {
            System.out.println("str1 diferente de str2");
        }
    }
}

Result:

str1: teste, str2: teste
str1 igual a str2 //agora o resultado dá comparação diz que são iguais

References: String (Java Platform SE 7) / Object

    
03.02.2014 в 16:19
13

Only by completing the @Math response

The objects of class String have an interesting particularity. the JVM saves a pool of Strings , where it stores the Strings that passed in its code, to avoid having to keep loading repeated Strings, but how does it work?

A String will go to the pool if you instantiate String literally, like this:

String str1 = "text";

The value "text" is now stored in the pool

On the other hand, if you instantiate with the new keyword, the value used will not be equal to pool .

String str2 = new String("text");

What can be seen with a simple test.

System.out.println(str1 == str2); // Imprime false

Now if you want the String to be the same as the pool you can use the intern() method, a #

  

Returns the canonical representation for the string object.   A pool of strings, initially empty, is maintained privately by the String class.

     When the integer method is invoked, if the pool already contains the string equal to this String object as determined by the equals (Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

That is, if there already exists an object with the value of String in pool , it is returned, if it does not exist, that value is added there, and the reference that was added is returned . And we can prove it with another simple test.

System.out.println(str1 == str2.intern());
    
03.02.2014 в 18:57
2

Only use .equals ().

Example:

String a = "1";
String b = "2";

if(a.equals(b))
return true;
    
28.04.2015 в 23:09