Principais erros de desenvolvedores Kotlin iniciantes: de A a Z

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que até desenvolvedores inteligentes tropeçam no Kotlin

\n\n

Kotlin é uma linguagem elegante e poderosa que conquistou o coração de milhões de desenvolvedores. Mas sua concisão e flexibilidade escondem armadilhas, especialmente para iniciantes vindos de Java ou outras linguagens. Muitos acham que, como Kotlin é "mais compreensível" que Java, haverá menos erros. Na prática, é o contrário: a falta de compreensão da filosofia da linguagem leva a bugs difíceis de detectar.

\n\n

Neste artigo, analisaremos os principais erros de desenvolvedores Kotlin iniciantes — desde a simples ignorância do null safety até o uso incorreto de coroutines. Cada erro será ilustrado com um exemplo de código e uma dica prática de como evitá-lo.

\n\n

1. Null Safety: quando "?" salva e quando não

\n\n

1.1. Ignorar tipos nullable

\n

O erro mais comum é usar !! (not-null assertion) onde seria possível usar chamadas seguras. Iniciantes frequentemente escrevem:

\n\n
fun printLength(str: String?) {\n    println(str!!.length) // Lançará NPE se str == null\n}
\n\n

A abordagem correta é usar ?.let ou o operador elvis ?::

\n\n
fun printLength(str: String?) {\n    str?.let { println(it.length) } ?: println("String é null")\n}
\n\n

1.2. Esquecer do Smart Cast

\n

Kotlin converte tipos automaticamente após a verificação de null, mas iniciantes não percebem isso:

\n\n
fun process(value: Any?) {\n    if (value is String) {\n        // value já é String, não precisa de cast!\n        println(value.length) // Funciona sem (value as String).length\n    }\n}
\n\n

Dica: Confie no compilador. Use !! apenas se tiver 100% de certeza de que o valor não é null e estiver preparado para uma falha em caso de erro.

\n\n

2. Sealed Class e When: armadilhas da exaustividade

\n\n

2.1. Usar o else com sealed class

\n

Sealed classes foram criadas para que o compilador verifique se todas as opções foram tratadas. Mas iniciantes frequentemente adicionam else, matando toda a mágica:

\n\n
sealed class Result {\n    data class Success(val data: String) : Result()\n    data class Error(val message: String) : Result()\n}\n\nfun handleResult(result: Result) {\n    when (result) {\n        is Result.Success -> println(result.data)\n        is Result.Error -> println(result.message)\n        else -> {} // Erro! Se adicionar uma nova subclasse, o compilador não avisará\n    }\n}
\n\n

O correto é não usar else:

\n\n
fun handleResult(result: Result) {\n    when (result) {\n        is Result.Success -> println(result.data)\n        is Result.Error -> println(result.message)\n    } // O compilador emitirá um erro se nem todos os ramos forem cobertos\n}
\n\n

2.2. Confundir sealed class com enum

\n

Iniciantes frequentemente escolhem enum onde precisam de sealed class. Lembre-se: enum é para um conjunto finito de constantes, sealed class é para uma hierarquia com dados diferentes em cada subclasse.

\n\n

3. Scope Functions: apply, let, run, with, also — como não se confundir

\n\n

3.1. Misturar contexto: this vs it

\n

A confusão mais comum é quando o iniciante usa apply (contexto — this) para operações onde é necessário let (contexto — it):

\n\n
data class User(var name: String, var age: Int)\n\nfun initUser(): User {\n    return User("Anônimo", 0).apply {\n        // this — é User\n        name = "João"\n        age = 25\n    }\n}\n\nfun printUserInfo(user: User?) {\n    user?.let { \n        // it — é user\n        println("Nome: ${it.name}, Idade: ${it.age}")\n    }\n}
\n\n

3.2. Cadeias de scope functions sem sentido

\n

Iniciantes adoram escrever cadeias como:

\n\n
list?.let { it.filter { it > 5 }.also { println(it) } }

Blogs

Book Recommendations