Por que Kotlin "tirou" de nós add, remove e put? Entendendo de uma vez por todas
\n\nSe você já programou em Java e depois migrou para Kotlin, certamente já passou por aquele momento de leve confusão. Você cria um List, quer adicionar um elemento — escreve .add(), e o ambiente de desenvolvimento destaca em vermelho. Ou tenta inserir um valor em um Map usando .put() — e novamente um erro.
Familiar? Pois é! A pergunta "Kotlin's List missing "add", "remove", Map missing "put", etc?" no Stack Overflow acumulou milhares de visualizações e dezenas de comentários. É uma verdadeira pedra no sapato para iniciantes, e até desenvolvedores experientes às vezes se pegam pensando: "Cadê meus métodos de sempre?"
\n\nNeste artigo, não vamos apenas responder a essa pergunta. Vamos mostrar como a filosofia do Kotlin transforma essa "falta" na sua maior vantagem. Você aprenderá as melhores práticas para trabalhar com coleções em 2025, saberá escolher o tipo correto de coleção e deixará de se confundir entre listOf e mutableListOf. Vamos lá!
Qual é o segredo? Imutabilidade como estilo de vida
\n\nA primeira coisa a entender: Kotlin foi projetado desde o início como uma linguagem que incentiva um código seguro e previsível. Um dos principais princípios é a imutabilidade (immutability) por padrão.
\n\nEm Java, você tem uma única interface List, e ela sempre contém métodos como add(), remove(), set() e assim por diante. Mesmo se você criar uma lista com List.of() (Java 9+), ainda terá acesso a esses métodos — eles apenas lançam uma exceção em tempo de execução. Isso é incômodo e inseguro.
Kotlin seguiu um caminho diferente. Ele dividiu as coleções em dois tipos:
\n\n- \n
- Imutáveis (somente leitura):
List,Set,Map— não possuem métodos que alteram o conteúdo. \n - Mutáveis (mutáveis):
MutableList,MutableSet,MutableMap— estes sim possuem todos os conhecidosadd,remove,put. \n
É por isso que listOf(1, 2, 3) não tem o método .add(). Ele retorna uma lista imutável. Já mutableListOf(1, 2, 3) retorna uma mutável, e esta possui .add().
Parece lógico? Vamos ver no código.
\n\nExemplos: o que funciona e o que não funciona
\n\nAqui está uma situação clássica que confunde iniciantes:
\n\n// ❌ Erro! List não tem add()\nval fruits = listOf("apple", "banana")\nfruits.add("orange") // Erro de compilação\n\n// ✅ Correto: usar MutableList\nval mutableFruits = mutableListOf("apple", "banana")\nmutableFruits.add("orange") // Agora funciona!\nprintln(mutableFruits) // [apple, banana, orange]\n\n\nCom Map, a mesma história:
\n\n// ❌ Erro! Map não tem put()\nval capitals = mapOf("Russia" to "Moscow", "France" to "Paris")\ncapitals.put("Germany", "Berlin") // Erro de compilação\n\n// ✅ Correto: usar MutableMap\nval mutableCapitals = mutableMapOf("Russia" to "Moscow", "France" to "Paris")\nmutableCapitals.put("Germany", "Berlin")\n// Ou de forma ainda mais curta:\nmutableCapitals["Germany"] = "Berlin"\nprintln(mutableCapitals) // {Russia=Moscow, France=Paris, Germany=Berlin}\n\n\nObserve: para MutableMap, você pode usar os colchetes operacionais [] — que é o put() por baixo dos panos. Muito prático!
Mas por quê? Por que Kotlin complica tanto a vida?
\n\nÀ primeira vista, parece uma dor de cabeça desnecessária. Por que memorizar dois tipos de coleções? Na verdade, é uma solução genial. Aqui estão três razões principais:
\n\n1. Segurança em nível de tipos
\nO compilador agora garante que você não altere acidentalmente uma lista que deveria ser