¿Es confiable el método afirmativo de Java?


199

Sé que ==tiene algunos problemas al comparar dos Strings. Parece que String.equals()es un mejor enfoque. Bueno, estoy haciendo pruebas JUnit y mi inclinación es usar assertEquals(str1, str2). ¿Es esta una forma confiable de afirmar que dos cadenas contienen el mismo contenido? yo usaríaassertTrue(str1.equals(str2)) , pero entonces no obtienes el beneficio de ver cuáles son los valores esperados y reales en caso de falla.

En una nota relacionada, ¿alguien tiene un enlace a una página o hilo que explique claramente los problemas str1 == str2?


1
Si no está seguro, puede leer el código o el Javadoc. Por cierto, si desea probar que son el mismo objeto, puede usar afirmar lo mismo.
Peter Lawrey

2
Si str1 y str2 son nulos, afirmarEquals () es verdadero, pero afirmarTrue (str1.equals (str2)) produce una excepción. El primer ejemplo también imprimirá un mensaje de error útil como el contenido de str1 y str2, el segundo no.
Peter Lawrey el

Respuestas:


274

Usted debe siempre utilizar .equals()cuando se comparan Stringsen Java.

JUnit llama al .equals()método para determinar la igualdad en el métodoassertEquals(Object o1, Object o2) .

Entonces, definitivamente estás seguro de usar assertEquals(string1, string2). (Porque Strings son Objects)

Aquí hay un enlace a una gran pregunta de Stackoverflow con respecto a algunas de las diferencias entre ==y .equals().


12
IIRC afirmarEquals () tiene éxito si ambas cadenas son nulas. Si esto no es lo que desea, entonces llame a afirmarNotNull () también.
finnw

10
Además, si quieres prueba para ==, puede llamar al (assertSame)
James

77
Yo no diría siempre ; a veces se desea la igualdad de referencia, incluso para cadenas.
Karu

30

assertEqualsusa el equalsmétodo de comparación. Hay una afirmación diferente assertSame, que utiliza el ==operador.

Para comprender por ==qué no debe usarse con cadenas, debe comprender lo que ==hace: hace una verificación de identidad. Es decir, a == bcomprueba para ver si ay se brefieren al mismo objeto . Está integrado en el lenguaje, y su comportamiento no puede ser cambiado por diferentes clases. El equalsmétodo, por otro lado, puede ser anulado por clases. Si bien su comportamiento predeterminado (en la Objectclase) es hacer una verificación de identidad utilizando el ==operador, muchas clases, incluso String, la anulan para hacer una verificación de "equivalencia". En el caso de String, en lugar de verificar si ay hacer breferencia al mismo objeto,a.equals(b) comprueba si los objetos a los que se refieren son cadenas que contienen exactamente los mismos caracteres.

Tiempo de analogía: imagine que cada Stringobjeto es un pedazo de papel con algo escrito en él. Digamos que tengo dos pedazos de papel con "Foo" escrito en ellos, y otro con "Bar" escrito en él. Si tomo los dos primeros trozos de papel y los uso ==para compararlos, se devolverá falseporque esencialmente se pregunta "¿son estos el mismo trozo de papel?". Ni siquiera necesita mirar lo que está escrito en el papel. El hecho de que le esté dando dos hojas de papel (en lugar de la misma dos veces) significa que volverá false. equalsSin embargo, si lo uso , el equalsmétodo leerá las dos hojas de papel y verá que dicen lo mismo ("Foo"), y así volverá true.

La parte que se confunde con las cadenas es que Java tiene un concepto de cadenas "internas", y esto (efectivamente) se realiza automáticamente en cualquier literal de cadena en su código. Esto significa que si tiene dos literales de cadena equivalentes en su código (incluso si están en clases diferentes), ambos se referirán al mismo Stringobjeto. Esto hace que el ==operador regrese con truemás frecuencia de lo que cabría esperar.


"Es decir, a == b verifica si a y b son el mismo objeto". Técnicamente, comprueba si a y b se REFIEREN al mismo objeto, ya que ayb son referencias. A menos que esté muy equivocado.
bob

@ user1903064 eso es correcto. Dado que las variables no primitivas solo pueden contener referencias en Java, es común omitir el nivel adicional de indirección cuando se habla de ellas, pero estoy de acuerdo en que en este caso ser más explícito es beneficioso. He actualizado la respuesta. ¡Gracias por la sugerencia!
Laurence Gonsalves

7

En pocas palabras: puede tener dos objetos de cadena que contienen los mismos caracteres pero son objetos diferentes (en diferentes ubicaciones de memoria). El operador == comprueba si dos referencias apuntan al mismo objeto (ubicación de memoria), pero el método equals () comprueba si los caracteres son iguales.

Por lo general, está interesado en verificar si dos cadenas contienen los mismos caracteres, no si apuntan a la misma ubicación de memoria.


4
public class StringEqualityTest extends TestCase {
    public void testEquality() throws Exception {
        String a = "abcde";
        String b = new String(a);
        assertTrue(a.equals(b));
        assertFalse(a == b);
        assertEquals(a, b);
    }
}

3

Sí, se usa todo el tiempo para las pruebas. Es muy probable que el marco de prueba use .equals () para comparaciones como estas.

A continuación hay un enlace que explica el "error de igualdad de cadena". Esencialmente, las cadenas en Java son objetos, y cuando se compara la igualdad de objetos, generalmente se comparan en función de la dirección de memoria y no por contenido. Debido a esto, dos cadenas no ocuparán la misma dirección, incluso si su contenido es idéntico, por lo que no coincidirán correctamente, aunque tengan el mismo aspecto cuando se impriman.

http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/


3

El JUnit assertEquals(obj1, obj2)sí llama obj1.equals(obj2).

También hay assertSame(obj1, obj2)qué hace obj1 == obj2(es decir, verifica eso obj1y hace obj2referencia a la misma instancia), que es lo que está tratando de evitar.

Entonces estás bien.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.