How to compare Strings in Java?

Asked

Viewed 106,387 times

59

The operator == says that strings are different, they store the same literal value, see the 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");
        }
    }
}

Upshot:

str1: teste, str2: teste
str1 diferente de str2

How to compare the literal value of Strings?

4 answers

51


Playing with the == and with the pool strings

Java uses a mechanism called String interning, putting the strings in a pool to try to store only one copy of each string in memory.

When Java finds String literals in the code, it always returns the same String instance, which points to an input in the pool internal JVM. It is therefore possible to use the == to compare two variables that receive String literals:

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

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

Even, as Java treats String literals as instances it is possible to compare a literal directly, thus:

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

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

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

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

But, however, in the meantime, that doesn’t mean we have two entries from "str" in the pool Java. How can we verify this? Using the method String.intern(), that returns a reference to the String that is in pool. Example:

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

Applying this to the question example, 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 equals str2

All very interesting. But, what if we created a string in a dazzling way?

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 the equals()?

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

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

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

Also, add a Strings in pool can also be an "expensive" operation. In addition to being required to check if the String already exists, Java will probably have to handle concurrent accesses.

And finally, a major drawback is the code becoming more prone to bugs (error prone), since it is necessary that the developer always put the intern() when necessary.

Other forms of comparison

Going a little beyond the exact comparison of Strings, we have other interesting ways of comparison:

Case insensitive (without regard to upper and lower case)

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 method compareTo returns:

  • 1 if the first string is larger than the second string
  • 0 if they are equal
  • -1 if the first string is smaller than the second string

Begins 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 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 for previous versions.

  • 4

    A real lesson on string comparison. Congratulations!

39

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

.equals() is a class method Object, which compares the values of literals stored by objects, so this method should be used to compare literal values 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");
        }
    }
}

Upshot:

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

14

Just complementing @Math’s reply

The objects of the class String has an interesting feature. the JVM keeps a string pool, where it stores the Strings that have passed your code, to avoid having to carry Repeated Strings, but how it works?

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

String str1 = "text";

The value "text" is now stored in pool

On the other hand if you instantiate with the keyword new, the value used shall not be that of pool, even if it’s the same.

String str2 = new String("text");

What can be seen with a simple test.

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

Now if you want her String be the same as pool can use the method intern(), to documentation his says the following:

Returns a Canonical representation for the string Object. A pool of strings, initially Empty, is maintained privately by the class String.

When the Intern method is Invoked, if the pool already contains a 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 is already an object with the value of String in the pool, it is returned, if it does not exist, this 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());
  • 5

    +1 Excellent placement! pool de Strings is something that took me a long time to know that existed and that can fool you in some situations. Important to know.

3

Use only . equals().

Example:

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

if(a.equals(b))
return true;
  • 7

    a.equals(b) already returns true/false.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.