Comparando cadenas con Java

En este tutorial, compararemos cadenas en Java utilizando métodos básicos y la biblioteca Apache Commons,

Introducción

En este tutorial, nos sumergiremos en Comparación de cadenas en Java.

La comparación de cadenas es una operación común en todos los idiomas. La capacidad de comprobar si una cadena es igual a otra nos permite realizar comprobaciones fundamentales y alterar el flujo del código.

El operador '=='

El operador == es uno de los primeros operadores que se aprenden al sumergirse en un nuevo lenguaje, generalmente para comparar tipos de datos primitivos como ints.

Echemos un vistazo a cómo podemos comparar dos objetos String con el operador ==:

1
2
3
4
5
6
String s1 = "Hello";
String s2 = "Hello";
String s3 = "World";

System.out.println(s1 == s2);
System.out.println(s2 == s3);

Esto devolvería:

1
2
true
false

Esto es lo esperado: s1 == s2 y s2 != s3. Sin embargo, reescribamos esto un poco en:

1
2
3
4
String s1 = "Hello";
String s2 = new String("Hello");

System.out.println(s1 == s2);

Esto devuelve:

1
false

Esto se debe a que el operador == no verifica la igualdad. Comprueba la identidad.

En otras palabras, no compara el valor de Strings - compara referencias de objetos.

El s1 es una variable de referencia al mismo objeto en la memoria al que hace referencia s2. Esto se debe a que String Pool no crea nuevos objetos si intentamos crear una instancia de String con un valor ya existente.

Sin embargo, cuando creamos una instancia de s2 con la palabra clave nuevo, le decimos explícitamente a la JVM que queremos un objeto nuevo. Entonces, a pesar de que tienen el mismo valor de cadena, las variables de referencia s1 y s2 se refieren a diferentes objetos y, por lo tanto, el operador == devuelve falso.

método de igualdad()

El método equals() suele ser el camino a seguir cuando se comparan los contenidos de Strings. Es sensible a mayúsculas y minúsculas y compara cada carácter de la cadena con cada carácter de la otra cadena:

1
2
3
4
String s1 = "Hello";
String s2 = new String("Hello");

System.out.println(s1.equals(s2));

Esto siempre devolverá:

1
true

Ya sea que escribimos s1.equals(s2) o s2.equals(s1), el resultado sería el mismo.

equals() es seguro frente a valores nulos, lo que significa que comprueba los valores nulos por usted. Si comparamos un valor que no es nulo con un valor nulo, lógicamente, el resultado es falso:

1
2
3
4
String s1 = "Hello";
String s2 = null;

System.out.println(s1.equals(s2));
1
false

método equalsIgnoreCase()

Dado que equals() distingue entre mayúsculas y minúsculas, en casos como Hola y hola, devolverá falso. Estos realmente no son iguales si el caso es importante. Sin embargo, en algunas situaciones, el caso realmente no es importante. Solo le gustaría verificar si los caracteres en sí son los mismos, independientemente del caso.

Para eso, usamos el método equalsIgnoreCase():

1
2
3
4
5
String s1 = "Hello";
String s2 = "hello";

System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2));

Esto resulta en:

1
2
false
true

método compareTo()

El método compareTo() funciona de manera diferente al método equals(). El método compareTo() comprueba el valor lexigográfico de la cadena.

Si comparamos ‘s1’ con ‘s2’, si el valor lexicográfico de ‘s1’ es mayor que el de ‘s2’, el método devolverá un valor positivo. Si es menor, el método devolverá un valor negativo. Si son iguales, el método devolverá 0.

Este método es muy útil si desea clasificar las palabras en orden lexicográfico:

1
2
3
4
String s1 = "a";
String s2 = "b";

System.out.println(s1.compareTo(s2));

Esto devuelve:

1
-1

Dado que la diferencia en los valores Unicode para a y b es solo 1. Echemos un vistazo a otro ejemplo:

1
2
3
4
String s1 = "Hello World";
String s2 = "hello world";

System.out.println(s1.compareTo(s2));

Esto resulta en:

1
-32

método compareToIgnoreCase()

Del mismo modo, hay una versión de este método que no se preocupa por las mayúsculas y minúsculas de los caracteres. Por ejemplo, las dos cadenas anteriores:

1
2
3
4
String s1 = "Hello World";
String s2 = "hello world";

System.out.println(s1.compareToIgnoreCase(s2));

Ahora volvería:

1
0

método contentEquals()

contentEquals() es un método relativamente poco utilizado, ya que parece que es lo mismo que el método equals().

Es decir, el método equals() compara los objetos por igualdad. La clase String anula el comportamiento predeterminado para que compare los contenidos.

El método contentEquals() compara CharSequences y StringBuffers. Con él, no tienes que convertir un ‘StringBuffer’ en un ‘String’ para comparar; el método se encargará de eso por sí mismo:

1
2
3
4
5
6
7
8
String s1 = "aaaa";
StringBuffer s2 = new StringBuffer("");

for (int i = 0; i < 4; i++) {
    s2.append('a');
}

System.out.println(s1.contentEquals(s2));

Con el método anterior, no puedes comparar un String con un StringBuffer. De esta manera, puedes.

Este código devuelve:

1
true

StringUtils - Apache Commons

La biblioteca Apache Commons es una biblioteca robusta llena de innumerables métodos y clases convenientes.

StringUtils es una clase de ayuda con un montón de operaciones relacionadas con String, incluidas las que verifican la igualdad.

StringUtils.equals()

El método equals() de la clase StringUtils funciona de la misma manera que esperaríamos en función de nuestra familiaridad con el método Object.equals():

1
2
3
4
5
6
String s1 = "Hello";
String s2 = new String("Hello");

System.out.println(StringUtils.equals(s1, s2));
System.out.println(StringUtils.equals(s1, null));
System.out.println(StringUtils.equals(null, null));

Esto devolvería:

1
2
3
true
false
true

También cuenta con seguridad nula y controles de valores nulos. La comparación de dos valores ’nulos’ devolverá ‘verdadero’.

StringUtils.equalsIgnoreCase()

El método equalsIgnoreCase() funciona de la misma manera:

1
2
3
4
5
6
String s1 = "Hello";
String s2 = new String("hello");

System.out.println(StringUtils.equalsIgnoreCase(s1, s2));
System.out.println(StringUtils.equalsIgnoreCase(s1, null));
System.out.println(StringUtils.equalsIgnoreCase(null, null));

Esto devuelve:

1
2
3
true
false
true

StringUtils.equalsAny()

equalsAny() es el primer método que hace algo completamente nuevo. Acepta un vararg String y CharSequence. Si cualquiera de los varargs se puede encontrar en la Cadena, devuelve verdadero:

1
2
System.out.println(StringUtils.equalsAny("Hello World", "Hello", "World"));
System.out.println(StringUtils.equalsAny("Java is great!", "Java", "great!"));

Esto devolvería:

1
2
true
true

Nota: El método distingue entre mayúsculas y minúsculas.

StringUtils.equalsAnyIgnoreCase()

Por supuesto, también tenemos una variante del método que no distingue entre mayúsculas y minúsculas:

1
2
System.out.println(StringUtils.equalsAnyIgnoreCase("Hello World", "HELLO", "world"));
System.out.println(StringUtils.equalsAnyIgnoreCase("Java is great!", "JavA", "GrEat!"));

Estos también devolverían:

1
2
true
true

StringUtils.compare()

El método compare() de la clase StringUtils funciona de la misma forma que el método compareTo() de la clase String. Sin embargo, este método de conveniencia es seguro contra nulos a diferencia de la implementación oficial.

Sigue la idea de que un valor “nulo” es lexicográficamente más pequeño que un valor no “nulo”, lo que tiene mucho sentido.

1
2
3
4
String s1 = "a";
String s2 = "b";

System.out.println(StringUtils.compare(s1, s2));

Esto devuelve:

1
-1

StringUtils.compareIgnoreCase()

Finalmente, la versión que no distingue entre mayúsculas y minúsculas del método anterior - compareIgnoreCase(). Compara el valor lexicográfico de Strings, sin considerar el caso:

1
2
3
4
String s1 = "A";
String s2 = "a";

System.out.println(StringUtils.compareIgnoreCase(s1, s2));

Esto normalmente devolvería -32 ya que las letras minúsculas están separadas de sus contrapartes mayúsculas por 32 lugares. Sin embargo, esto devuelve:

1
0

Conclusión

La comparación de cadenas en Java, como en otros lenguajes, es una tarea común. Hay bastantes maneras de hacerlo, tanto usando métodos integrados como la biblioteca Apache Commons.