En Kotlin hay dos operadores para la comparación:
== — comparación estructural (equivalente a .equals()). Comprueba el contenido: a == b invoca a?.equals(b) ?: (b == null).=== — comparación de referencia. Verifica si ambas variables apuntan al mismo objeto: a === b es equivalente a Java a == b para objetos.Para tipos primitivos (por ejemplo, Int): == y === pueden comportarse igual debido al autoboxing, pero en general se debe usar ==.
val a = "Kotlin" val b = "Kotlin" val c = a println(a == b) // true (comparación de contenido) println(a === b) // false (referencias diferentes — cadenas internadas depende del compilador) println(a === c) // true (el mismo objeto)
¿Cuál es la diferencia entre a.equals(b) y a == b en Kotlin?
Algunos afirman que no hay diferencia, sin embargo, si a es nullable, la llamada a a.equals(b) lanzará NullPointerException, mientras que a == b es seguro y retornará true si ambos son null, o false si solo uno de ellos es null.
Ejemplo:
val a: String? = null val b: String? = null println(a == b) // true println(a?.equals(b)) // null (y no true, pero no una excepción) println(a.equals(b)) // NullPointerException
Historia
En un gran proyecto, se comparaban activamente cadenas nullable a través de a.equals(b), sin sospechar que al tener a == null la aplicación fallaba. El error se repetía bastante raro, pero causaba fallos fatales en producción — se corrigió cambiando a a == b.
Historia
Al comparar objetos mediante === se esperaba una comparación de contenido, pero === verifica la identidad de los objetos — se descubrió que dos cadenas diferentes con el mismo contenido no son iguales a través de ===, lo que rompió la lógica de caché de datos.
Historia
Al trabajar con valores Int encapsulados (por ejemplo, de colecciones), los desarrolladores los comparaban con === y obtenían resultados inesperados debido a que las instancias de objeto de diferentes números no se internan necesariamente como primitivos. Esto llevaba a un comportamiento incorrecto al trabajar con colecciones de objetos.