ProgramaciónDesarrollador Android de nivel medio

¿Cómo se implementa la inmutabilidad (immutability) de colecciones y objetos en Kotlin, y en qué se diferencia la práctica de Java?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

Historia de la cuestión:

En Java, la inmutabilidad de las colecciones se logra a través de envolturas como Collections.unmodifiableList() y el diseño de clases inmutables manualmente (campos final, ausencia de setters). En la práctica del desarrollo de Android y en el lado del servidor, esto se volvía costoso e incómodo, y la seguridad de los hilos y la previsibilidad de los datos se perdían.

Problema:

Las colecciones de Java no son seguras por defecto; siempre se puede obtener una referencia y modificar el objeto. Esto complica el control sobre la mutabilidad, especialmente en entornos multihilo, y conduce a errores difíciles de detectar.

Solución:

Kotlin se diseñó desde el principio con una separación entre colecciones de solo lectura y mutables, y la creación de objetos realmente inmutables se volvió más fácil gracias a val, data class y List/Set/Map sin el prefijo mutable. Además, se utiliza la copia a través de los métodos copy().

Ejemplo de código:

val nums: List<Int> = listOf(1, 2, 3) // lista inmutable // nums.add(4) // error de compilación val user = User(name = "Alex", age = 30) val updated = user.copy(age = 31) // Ejemplo con un mapa inmutable val state: Map<String, Int> = mapOf("a" to 1, "b" to 2)

Características clave:

  • La compilación al intentar modificar una colección de solo lectura generará un error
  • En Kotlin, val garantiza la inmutabilidad de la referencia, pero no necesariamente del objeto
  • Para ser realmente inmutable, utilice solo interfaces de solo lectura y prohíba la modificación del estado interno

Preguntas capciosas.

¿Garantiza val la inmutabilidad absoluta del objeto contenido?

¡No! val garantiza solo que la variable no puede apuntar a otro objeto, pero se pueden cambiar los campos del objeto (si las propiedades internas son var).

¿Se puede obtener un objeto mutable de una colección de solo lectura?

Sí — si la colección contiene un objeto mutable, se puede cambiar su estado a pesar de la interfaz de solo lectura de la colección.

data class User(var name: String) val users: List<User> = listOf(User("Vasya")) users[0].name = "Petya" // permitido

¿Qué sucederá al convertir List<Int> a MutableList<Int> a través de as?

Se compilará, pero lanzará una ClassCastException en tiempo de ejecución si el tipo original era una interfaz de solo lectura.

Errores típicos y antipatrón

  • Confundir val como una garantía absoluta de inmutabilidad del objeto
  • Manipulación de referencias a objetos mutables dentro de colecciones "inmutables"
  • Conversión de colecciones de solo lectura a mutables

Ejemplo de la vida real

Caso negativo

Una aplicación de Android almacena el estado en val List<User>, creyendo que es inmutable. Uno de los desarrolladores modifica user.name. En otro fragmento, la lista actualizada muestra inesperadamente datos inconsistentes: el error aparece en la versión final.

Ventajas:

  • Rápida manipulación de colecciones

Desventajas:

  • Pérdida de control sobre las mutaciones
  • Mutabilidad oculta

Caso positivo

Uso de data class inmutable solo con campos val, filtrando el acceso a objetos internos, actualización del estado a través de copy().

Ventajas:

  • Alta previsibilidad y seguridad en hilos
  • Ausencia de efectos secundarios inesperados

Desventajas:

  • A veces requiere más asignaciones y copias
  • No todas las bibliotecas de terceros proporcionan objetos realmente inmutables