Neste tutorial, vamos explorar as estruturas condicionais do Kotlin, incluindo if, when e como elas funcionam como expressões que retornam valores. Você vai aprender a controlar o fluxo do seu programa de forma clara, concisa e idiomática, aproveitando recursos exclusivos que Kotlin oferece em relação a outras linguagens.

O if como Expressão

Em Kotlin, o if funciona de duas formas: como instrução tradicional (statement) e como expressão que retorna um valor. Essa segunda forma é extremamente poderosa e elimina a necessidade do operador ternário que existe em Java e outras linguagens.

Quando usado como instrução, o if funciona de maneira semelhante a qualquer outra linguagem de programação. Você define uma condição e o bloco de código que deve ser executado caso a condição seja verdadeira.

fun main() {
    val idade = 20

    // if como instrução (statement)
    if (idade >= 18) {
        println("Você é maior de idade.")
    } else {
        println("Você é menor de idade.")
    }

    // if como expressão (retorna um valor)
    val status = if (idade >= 18) "maior de idade" else "menor de idade"
    println("Status: $status")

    // if-else if encadeado como expressão
    val nota = 7.5
    val conceito = if (nota >= 9.0) {
        "Excelente"
    } else if (nota >= 7.0) {
        "Bom"
    } else if (nota >= 5.0) {
        "Regular"
    } else {
        "Insuficiente"
    }
    println("Nota: $nota — Conceito: $conceito")

    // if com blocos maiores (última expressão é o valor retornado)
    val numero = 15
    val resultado = if (numero % 2 == 0) {
        println("Analisando número par...")
        "par"
    } else {
        println("Analisando número ímpar...")
        "ímpar"
    }
    println("O número $numero é $resultado")
}

Quando o if é usado como expressão, o último valor de cada bloco é o valor retornado. Isso significa que em blocos com múltiplas linhas, apenas a última linha define o valor de retorno. Note também que, quando usado como expressão, o ramo else é obrigatório — o compilador precisa garantir que sempre haverá um valor retornado.

Essa abordagem elimina completamente a necessidade do operador ternário (condição ? verdadeiro : falso) que existe em Java, C e JavaScript. Em Kotlin, o if como expressão é a forma idiomática de fazer a mesma coisa, mas de maneira mais legível e com suporte a blocos de código completos.

A Expressão When: O Switch Turbinado

A expressão when é uma das funcionalidades mais versáteis do Kotlin. Ela substitui e supera o switch de Java, oferecendo verificação de igualdade, ranges, verificação de tipo, condições arbitrárias e muito mais, tudo em uma sintaxe limpa e expressiva.

fun main() {
    // when básico (substitui switch/case)
    val diaDaSemana = 3
    val nomeDia = when (diaDaSemana) {
        1 -> "Segunda-feira"
        2 -> "Terça-feira"
        3 -> "Quarta-feira"
        4 -> "Quinta-feira"
        5 -> "Sexta-feira"
        6 -> "Sábado"
        7 -> "Domingo"
        else -> "Dia inválido"
    }
    println("Dia $diaDaSemana = $nomeDia")

    // when com múltiplos valores no mesmo ramo
    val mes = 8
    val estacao = when (mes) {
        12, 1, 2 -> "Verão"
        3, 4, 5 -> "Outono"
        6, 7, 8 -> "Inverno"
        9, 10, 11 -> "Primavera"
        else -> "Mês inválido"
    }
    println("Mês $mes = $estacao")

    // when com ranges (intervalos)
    val nota = 85
    val classificacao = when (nota) {
        in 90..100 -> "A"
        in 80..89 -> "B"
        in 70..79 -> "C"
        in 60..69 -> "D"
        in 0..59 -> "F"
        else -> "Nota inválida"
    }
    println("Nota $nota = $classificacao")

    // when com verificação de tipo (is)
    val valor: Any = "Kotlin Brasil"
    when (valor) {
        is String -> println("É uma String com ${valor.length} caracteres")
        is Int -> println("É um inteiro: $valor")
        is Boolean -> println("É um booleano: $valor")
        else -> println("Tipo desconhecido")
    }
}

Observe como o when é mais poderoso que o switch tradicional. Ele não precisa de break em cada caso (não há fall-through), suporta ranges com in, verificação de tipo com is (incluindo smart cast automático), e pode agrupar múltiplos valores com vírgula. Quando usado como expressão, o ramo else é obrigatório, a menos que o compilador possa garantir que todos os casos possíveis estão cobertos.

When sem Argumento e Condições Complexas

O when pode ser usado sem argumento, funcionando como uma sequência de if-else if mais elegante. Nesse formato, cada ramo contém uma condição booleana independente.

fun main() {
    val temperatura = 32
    val umidade = 75

    // when sem argumento — como if-else if mais limpo
    val recomendacao = when {
        temperatura > 35 && umidade > 80 -> "Calor extremo! Evite atividades ao ar livre."
        temperatura > 30 -> "Está quente. Beba bastante água."
        temperatura in 20..30 -> "Temperatura agradável para atividades externas."
        temperatura in 10..19 -> "Está fresco. Leve um casaco."
        temperatura < 10 -> "Está frio! Vista-se bem."
        else -> "Condição não prevista."
    }
    println("Temperatura: ${temperatura}°C — $recomendacao")

    // when com blocos de código
    val numero = -5
    when {
        numero > 0 -> {
            println("$numero é positivo")
            println("Seu dobro é ${numero * 2}")
        }
        numero < 0 -> {
            println("$numero é negativo")
            println("Seu valor absoluto é ${-numero}")
        }
        else -> {
            println("$numero é zero")
        }
    }

    // when em função de classificação
    val imc = 24.5
    val classificacaoIMC = when {
        imc < 18.5 -> "Abaixo do peso"
        imc < 25.0 -> "Peso normal"
        imc < 30.0 -> "Sobrepeso"
        imc < 35.0 -> "Obesidade grau I"
        imc < 40.0 -> "Obesidade grau II"
        else -> "Obesidade grau III"
    }
    println("IMC: $imc — Classificação: $classificacaoIMC")
}

Essa forma do when sem argumento é particularmente útil quando as condições envolvem variáveis diferentes ou expressões complexas que não se encaixam naturalmente em um when com argumento. Ela torna cadeias longas de if-else if muito mais legíveis e organizadas.

When com Sealed Classes e Enums

O when tem uma integração especial com sealed classes e enums. Quando todos os subtipos possíveis são cobertos, o compilador não exige o ramo else, pois sabe que todas as possibilidades estão contempladas. Esse recurso é extremamente valioso para garantir que você não esqueceu de tratar algum caso.

Veremos esse tópico em detalhes no tutorial de Sealed Classes, mas é importante saber desde já que essa combinação é uma das ferramentas mais poderosas do Kotlin para escrever código seguro e expressivo.

Comparação entre Estruturas Condicionais

Para escolher a melhor estrutura condicional para cada situação, considere as seguintes orientações. Use if simples quando há apenas uma condição a verificar, ou quando você precisa de uma lógica verdadeiro/falso direta. Use if-else como expressão quando precisa atribuir um valor com base em uma condição binária, substituindo o operador ternário. Use when com argumento quando precisa comparar uma variável contra múltiplos valores possíveis, e use when sem argumento quando tem múltiplas condições independentes que não se relacionam a uma única variável.

O when é geralmente preferível a cadeias longas de if-else if porque é mais legível, menos propenso a erros e mais fácil de manter. A regra geral é: se você tem mais de dois ramos condicionais, considere usar when.

Dicas e Erros Comuns

Ao trabalhar com estruturas condicionais em Kotlin, evite estes erros frequentes:

  1. Esquecer o else quando when é usado como expressão: se você está atribuindo o resultado de um when a uma variável, precisa de um ramo else (exceto com sealed classes/enums exaustivos). Sem ele, o compilador não tem garantia de que sempre haverá um valor.

  2. Usar if encadeado onde when seria mais claro: cadeias de if-else if com mais de três condições ficam muito mais legíveis como when. Refatore sempre que possível.

  3. Não aproveitar o when como expressão: muitos desenvolvedores vindos de Java usam when apenas como statement e depois atribuem o valor manualmente. Use-o como expressão diretamente.

  4. Esquecer que in funciona com ranges no when: em vez de escrever valor >= 10 && valor <= 20, use valor in 10..20 para código mais idiomático e legível.

  5. Não usar smart cast após verificação is: depois de verificar o tipo com is dentro de um when, o compilador já faz o cast automaticamente. Não faça cast manual desnecessário.

  6. Usar comparação com true ou false: escreva if (ativo) em vez de if (ativo == true). A segunda forma é redundante e considerada não-idiomática em Kotlin.

Conclusão e Próximos Passos

As estruturas condicionais em Kotlin são mais expressivas e seguras do que em muitas outras linguagens. O uso de if e when como expressões é um dos recursos que tornam o código Kotlin mais conciso e elegante, eliminando variáveis temporárias e reduzindo a chance de erros. A integração do when com o sistema de tipos, especialmente com sealed classes e smart casts, é uma ferramenta poderosa que você vai usar constantemente.

Para continuar aprendendo, recomendo os próximos tutoriais:

Pratique criando programas que usem when com diferentes tipos de condições. Um bom exercício é criar um conversor de unidades ou uma calculadora que use when para selecionar operações. Quanto mais você praticar, mais natural será escolher a estrutura condicional certa para cada situação.