¿Por qué Kotlin nos "quitó" add, remove y put? Aclaremos esto de una vez por todas
\n\nSi alguna vez has programado en Java y luego has pasado a Kotlin, seguramente te has encontrado con este momento de leve desconcierto. Creas un List, quieres agregarle un elemento — escribes .add(), y el entorno de desarrollo lo resalta en rojo. O intentas poner un valor en un Map mediante .put() — y de nuevo un error.
¿Te suena? ¡Claro que sí! La pregunta "Kotlin's List missing "add", "remove", Map missing "put", etc?" en Stack Overflow ha acumulado miles de visitas y decenas de comentarios. Es una verdadera piedra de tropiezo para los principiantes, e incluso los desarrolladores experimentados a veces se sorprenden pensando: "¿Y dónde están mis métodos habituales?"
\n\nEn este artículo no solo responderemos a esta pregunta. Mostraremos cómo la filosofía de Kotlin convierte esta "carencia" en tu principal ventaja. Conocerás las mejores prácticas para trabajar con colecciones en 2025, aprenderás a elegir el tipo de colección correcto y dejarás de confundirte entre listOf y mutableListOf. ¡Allá vamos!
¿Cuál es el meollo? La inmutabilidad como forma de vida
\n\nLo primero que hay que entender: Kotlin fue diseñado desde el principio como un lenguaje que fomenta un código seguro y predecible. Uno de los principios principales es la inmutabilidad (immutability) por defecto.
\n\nEn Java tienes una única interfaz List, y siempre contiene métodos como add(), remove(), set(), etc. Incluso si creas una lista mediante List.of() (Java 9+), sigues teniendo acceso a estos métodos — simplemente lanzan una excepción en tiempo de ejecución. Esto es incómodo e inseguro.
Kotlin tomó un camino diferente. Dividió las colecciones en dos tipos:
\n\n- \n
- Inmutables (solo lectura):
List,Set,Map— no tienen métodos que modifiquen el contenido. \n - Mutables:
MutableList,MutableSet,MutableMap— estos sí tienen todos los conocidosadd,remove,put. \n
Por eso listOf(1, 2, 3) no tiene el método .add(). Devuelve una lista inmutable. Mientras que mutableListOf(1, 2, 3) devuelve una mutable, y sí tiene .add().
¿Suena lógico? Veamos el código.
\n\nEjemplos: qué funciona y qué no
\n\nAquí tienes una situación clásica que confunde a los principiantes:
\n\n// ❌ ¡Error! List no tiene add()\nval fruits = listOf("apple", "banana")\nfruits.add("orange") // Error de compilación\n\n// ✅ Correcto: usamos MutableList\nval mutableFruits = mutableListOf("apple", "banana")\nmutableFruits.add("orange") // ¡Ahora funciona!\nprintln(mutableFruits) // [apple, banana, orange]\n\n\nCon Map ocurre lo mismo:
\n\n// ❌ ¡Error! Map no tiene put()\nval capitals = mapOf("Russia" to "Moscow", "France" to "Paris")\ncapitals.put("Germany", "Berlin") // Error de compilación\n\n// ✅ Correcto: usamos MutableMap\nval mutableCapitals = mutableMapOf("Russia" to "Moscow", "France" to "Paris")\nmutableCapitals.put("Germany", "Berlin")\n// O incluso más corto:\nmutableCapitals["Germany"] = "Berlin"\nprintln(mutableCapitals) // {Russia=Moscow, France=Paris, Germany=Berlin}\n\n\nObserva: para MutableMap se pueden usar los corchetes de operador [] — que es put() bajo el capó. ¡Muy práctico!
¿Pero por qué? ¿Por qué Kotlin complica tanto la vida?
\n\nA primera vista, parece un dolor de cabeza innecesario. ¿Para qué recordar dos tipos de colecciones? En realidad, es una solución genial. Aquí tienes tres razones principales:
\n\n1. Seguridad a nivel de tipos
\nEl compilador ahora se asegura de que no modifiques accidentalmente una lista que debería ser