Por que a ordenação "simples" em Kotlin quebra o código?
\nOlá, colega! Se você já escreveu em Kotlin e tentou ordenar uma lista de tarefas primeiro por data e depois por prioridade, certamente já se deparou com uma situação em que o resultado parece um conjunto aleatório. Você não está sozinho — a pergunta "Sort collection by multiple fields in Kotlin" acumulou milhares de visualizações no Stack Overflow. Parece simples, não? Mas o diabo, como sempre, está nos detalhes.
\nNeste artigo, vamos analisar os principais erros ao ordenar por vários campos em Kotlin, que até desenvolvedores experientes cometem. Você aprenderá como funciona o sortedWith, por que compareBy e thenBy são seus melhores amigos e como não perder dados devido a null. Vamos lá!
Erro nº 1: Ordenar como em Java — usando Comparator manualmente
\nKotlin não é Java. Mas muitos, vindos do mundo Java, escrevem:
\nval list = listOf(\n User("Alice", 25),\n User("Bob", 20),\n User("Charlie", 25)\n)\n\nval sorted = list.sortedWith(Comparator { a, b ->\n val ageCompare = a.age.compareTo(b.age)\n if (ageCompare != 0) ageCompare else a.name.compareTo(b.name)\n})\n\nSim, funciona. Mas é terrivelmente ilegível, e você pode facilmente se perder em cadeias de if-else. Kotlin oferece uma maneira elegante — as funções comparadoras.
Como fazer corretamente?
\nval sorted = list.sortedWith(compareBy<User> { it.age }.thenBy { it.name })\n\nCurto, claro, sem lógica desnecessária. compareBy cria o comparador primário, e thenBy adiciona campos secundários. Isso é a ordenação por vários campos em Kotlin em sua forma ideal.
Erro nº 2: Ignorar null ao ordenar
\nSuponha que temos uma lista de tarefas onde deadline pode ser null. Se você simplesmente escrever:
tasks.sortedBy { it.deadline }\n\n…você obterá um NullPointerException. Kotlin é rigoroso com null, e isso é ótimo. Mas como proceder se null é algo normal?
\nSolução: nullsFirst / nullsLast
\nUse wrappers especiais:
\nval sorted = tasks.sortedWith(\n compareBy<Task>(nullsLast()) { it.deadline }\n .thenBy { it.priority }\n)\n\nAqui, nullsLast() coloca todas as datas nulas no final da lista. Existe também nullsFirst() — o contrário. Isso resolve o problema, e sua ordenação de coleções Kotlin se torna segura.
Erro nº 3: Confundir sortedBy com sortedWith
\nMuitos iniciantes escrevem:
\nlist.sortedBy { it.age }.sortedBy { it.name }\n\nE se surpreendem que a ordenação por nome "sobrescreve" a ordenação por idade. sortedBy cria uma nova lista a cada vez e ordena apenas por um campo. A última chamada é a que prevalece.
Como corrigir?
\nUse sortedWith com a cadeia compareBy:
list.sortedWith(compareBy({ it.age }, { it.name }))\n\nOu a versão multilinha para lógica complexa:
\nlist.sortedWith(compareBy<Person> { it.age }.thenByDescending { it.name })\n\nLembre-se: uma chamada de sortedWith — uma ordenação por vários campos.
\n\nErro nº 4: Ordenação em ordem inversa — no lugar errado
\nÀs vezes é necessário ordenar por idade em ordem crescente, mas por nome em ordem decrescente. O erro típico:
\nlist.sortedByDescending { it.age }.sortedBy { it.name }\n\nNovamente o mesmo problema — a segunda ordenação quebra a primeira. A abordagem correta:
\nval sorted = list.sortedWith(\n compareBy<Person> { it.age }\n .thenByDescending { it.name }\n)\n\nOu para controle total:
\nval sorted = list.sortedWith(\n compareBy(Person::age).thenByDescending(Person::name)\n)\n<