Principais erros de desenvolvedores Kotlin iniciantes: como evitá-los e escrever código limpo
Kotlin é uma linguagem moderna, concisa e segura que rapidamente ganhou popularidade no mundo do desenvolvimento Android e backend. No entanto, sua flexibilidade e açúcar sintático frequentemente confundem iniciantes. Neste artigo, vamos analisar 4 erros típicos que desenvolvedores Kotlin iniciantes cometem e mostrar como corrigi-los com exemplos de código.
1. Ignorar null safety e uso incorreto do operador !!
Uma das principais características do Kotlin é null safety. Mas muitos iniciantes, acostumados com Java, continuam usando !! (not-null assertion operator) sem pensar. Este é o caminho direto para NullPointerException.
Exemplo ruim:
fun getUserName(user: User?): String { return user!!.name // Se user == null, será NPE}Exemplo bom (trabalho seguro com nullable):
fun getUserNameSafe(user: User?): String { return user?.name ?: "Usuário desconhecido"}Use ?.let{}, ?: (operador elvis) e ?.run{} para acesso seguro. O operador !! só se justifica em casos raros quando você tem 100% de certeza que o valor não é null (por exemplo, em testes).
2. Uso incorreto de sealed classes e when
Sealed classes são uma ferramenta poderosa para modelar hierarquias limitadas. Mas iniciantes frequentemente esquecem que when deve ser exaustivo (exhaustive) ao trabalhar com sealed classes. Ou, ao contrário, usam else onde não é necessário.
Exemplo ruim (ramo omitido):
sealed class Result { data class Success(val data: String) : Result() data class Error(val message: String) : Result()}
fun handleResult(result: Result) { when (result) { is Result.Success -> println(result.data) // Ramo para Error está ausente — haverá um aviso }}Exemplo bom (when exaustivo):
fun handleResultExhaustive(result: Result) { when (result) { is Result.Success -> println(result.data) is Result.Error -> println(result.message) } // O compilador não exige else, pois todas as variantes estão cobertas}Se você adicionar um novo ramo à sealed class, o compilador indicará onde o when precisa ser atualizado. Isso protege o código de erros durante a refatoração.
3. Abuso de coroutines: execução sem contexto e ignorando structured concurrency
Coroutines são uma excelente forma de trabalhar com assincronia, mas iniciantes frequentemente as executam sem o contexto correto ou esquecem o structured concurrency. Isso leva a vazamentos de memória e tarefas em segundo plano incontroláveis.
Exemplo ruim (escopo global e perda de contexto):
fun loadData() { GlobalScope.launch { // Ruim! Vive enquanto a aplicação viver val data = fetchData() // Pode executar após o fechamento da Activity updateUI(data) // Erro: UI já foi destruída }}Exemplo bom (structured concurrency com viewModelScope):
class MyViewModel : ViewModel() { fun loadData() { viewModelScope.launch { val data = fetchData() updateUI(data) // Será cancelado automaticamente ao limpar a ViewModel } }}Sempre use coroutineScope, viewModelScope ou seu próprio CoroutineScope com um ciclo de vida claro. Evite GlobalScope em código de produção.
4. Sobrecarga de operadores sem compreender a semântica
Kotlin permite sobrecarregar operadores (+, -, in