Kotlin: Fluxo de Controle do Kotlin Explicado

Última atualização: 2026-08-26

O fluxo de controle do Kotlin não é apenas controle de fluxo — if e when são expressões com valores de retorno, tornando a lógica de roteamento de pedidos do Charlie ao mesmo tempo segura e concisa.

1. O que Você Aprenderá


2. A História Real de um Arquiteto

(1) Problema: Inferno do if-else Aninhado

O OrderProcessor Java do Charlie usava 5 níveis de if-else aninhados para rotear pedidos por status — 120 linhas apenas para decidir qual pipeline usar. Quando o novo membro Bob entrou, errou nas condições de ramificação 3 vezes, causando incidentes em produção.

(2) Solução: Expressão when do Kotlin

KOTLIN
// Limpo, exaustivo, verificado pelo compilador
fun route(order: Order): Pipeline = when (order.status) {
    Status.PENDING -> PendingPipeline
    Status.CONFIRMED -> if (order.total > 10_000) VipPipeline else StandardPipeline
    Status.SHIPPED -> TrackingPipeline
    Status.CANCELLED -> RefundPipeline
}

Verificação de exaustividade da expressão when + guarda do compilador: um ramo ausente é um erro de compilação. Bob nunca mais poderá introduzir tais bugs.


3. Expressão if

(1) if é uma Expressão com Valor de Retorno

KOTLIN
// if como expressão
val max = if (a > b) a else b

// Expressão if com múltiplos ramos
val category = if (total > 10_000) {
    println("Pedido de alto valor")
    "VIP"
} else if (total > 1_000) {
    "PRIORITY"
} else {
    "STANDARD"
}

(2) Expressão if Kotlin vs if Java

Dimensão Java if Kotlin if
Natureza Instrução Expressão
Valor de retorno Nenhum Valor da última expressão
Atribuição Precisa de variável extra val x = if(...)...
Operador ternário ?: if/else
KOTLIN
// Nenhum operador ternário necessário - if/else É o ternário
val discount = if (total > 5_000) 0.15 else if (total > 1_000) 0.10 else 0.0

4. when em Todas as Suas Formas

(1) Expressão when Básica

KOTLIN
// Correspondência exata
val label = when (status) {
    "PENDING" -> "Aguardando"
    "CONFIRMED" -> "Confirmado"
    else -> "Desconhecido"
}

// Múltiplos valores em um ramo
val isTerminal = when (status) {
    "SHIPPED", "DELIVERED", "CANCELLED" -> true
    else -> false
}

(2) Condições de Guarda (when com Guarda)

KOTLIN
// Ramos condicionais com 'in' e intervalos
val pipeline = when {
    status == "CANCELLED" -> "REFUND"
    total > 10_000 && priority == "URGENT" -> "VIP_EXPRESS"
    total > 10_000 -> "VIP"
    total > 1_000 -> "PRIORITY"
    status in listOf("NEW", "PENDING") -> "QUEUE"
    else -> "STANDARD"
}

(3) Vinculação de Variáveis e Desestruturação

KOTLIN
// Captura com sujeito do when
val result = when (val response = httpClient.call()) {
    is Success -> "OK: ${response.data}"
    is Error -> "Falhou: ${response.code}"
}
// response é smart-cast e disponível nos ramos

(4) Diagrama de Roteamento de Status de Pedido

100%
flowchart TD
    A[when order.status] --> B{PENDING}
    A --> C{CONFIRMED}
    A --> D{SHIPPED}
    A --> E{CANCELLED}
    B --> B1[Fila de Espera]
    C --> C1{total > 10000?}
    C1 -->|Sim| C2[Pipeline VIP]
    C1 -->|Não| C3[Pipeline Padrão]
    D --> D1[Pipeline de Rastreamento]
    E --> E1[Fila de Reembolso]

(5) Comparação das Formas do when

Forma Sintaxe Caso de Uso
Correspondência exata when(status) Enums / strings / constantes
Correspondência de múltiplos valores "A", "B" -> ... Múltiplos valores, mesmo ramo
Correspondência por intervalo in 1..10 Intervalos numéricos
Correspondência por tipo is String Roteamento por tipo
Condições de guarda when { ... } Combinações de condições complexas
Vinculação de variáveis when(val x = ...) Capturar valores computados

5. Loop for e Iteradores

(1) Loop for Básico

KOTLIN
// Iteração de intervalo
for (i in 1..10) { /* i de 1 a 10 */ }

// Iteração de lista
for (order in orders) { println(order.id) }

// Com índice
for ((index, order) in orders.withIndex()) {
    println("[$index] ${order.id}")
}

// Iteração de mapa
for ((id, status) in orderStatusMap) {
    println("$id: $status")
}

(2) Protocolo de Iterador

KOTLIN
// Qualquer classe com operator fun iterator() pode ser usada em loop for
class OrderBatch(val orders: List<Order>) {
    operator fun iterator(): Iterator<Order> = orders.iterator()
}

val batch = OrderBatch(orders)
for (order in batch) { /* funciona! */ }

(3) Comparação de Padrões do Loop for

Padrão Sintaxe Caso de Uso
Intervalo for (i in 1..10) Loops de contagem
Coleção for (o in orders) Iterar elementos
Com índice for ((i, o) in ...) Precisa do índice
Mapa for ((k,v) in map) Iteração chave-valor
Iterador personalizado operator fun iterator() Contêineres personalizados

6. Loop while

KOTLIN
// while padrão
var retryCount = 0
while (retryCount < 3) {
    val success = tryProcessOrder()
    if (success) break
    retryCount++
}

// do-while (executa pelo menos uma vez)
var input: String
do {
    input = readOrderStatus()
} while (input !in listOf("CONFIRM", "CANCEL"))

7. Rótulos e Retornos

(1) Rótulos de Loop

KOTLIN
// Rotular loop externo
loop@ for (batch in batches) {
    for (order in batch) {
        if (order.status == "CANCELLED") continue@loop  // Pular para o próximo lote
        if (order.total > 100_000) break@loop  // Parar todo o processamento
        process(order)
    }
}

(2) Retornos de Lambda

KOTLIN
// retorno de lambda (retorno local)
orders.forEach { order ->
    if (order.status == "SKIP") return@forEach  // Pular apenas este item
    process(order)
}

// retorno da função envolvente (retorno não local)
// Funciona apenas em funções inline
orders.forEach { order ->
    if (order.status == "FATAL") return  // Sai do main()
    process(order)
}

(3) Comparação de Tipos de Rótulos

Tipo de Rótulo Sintaxe Efeito
Rótulo de loop loop@ + break@loop Sair do loop especificado
Rótulo continue continue@loop Ir para a próxima iteração do loop especificado
Retorno local de lambda return@forEach Sair apenas do lambda atual
Retorno não local return Sair da função envolvente (apenas inline)

8. Exemplo Completo: Máquina de Estados de Pedidos do OrderProcessor

KOTLIN
// ============================================
// OrderProcessor - Roteamento Baseado em Status
// Funcionalidade: Roteamento completo de status de pedido com when
// ============================================

enum class Status { PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED }
data class Order(val id: String, val total: Double, val status: Status, val region: String)

fun routeOrder(order: Order): String = when (order.status) {
    Status.PENDING -> when {
        order.region == "EU" -> "EU_COMPLIANCE_QUEUE"
        order.total > 10_000 -> "HIGH_VALUE_QUEUE"
        else -> "STANDARD_QUEUE"
    }
    Status.CONFIRMED -> when {
        order.total > 5_000 -> "EXPRESS_SHIPPING"
        else -> "REGULAR_SHIPPING"
    }
    Status.SHIPPED -> "TRACKING_UPDATE"
    Status.DELIVERED -> "COMPLETION_QUEUE"
    Status.CANCELLED -> when {
        order.total > 1_000 -> "PRIORITY_REFUND"
        else -> "STANDARD_REFUND"
    }
}

fun processBatch(orders: List<Order>) {
    loop@ for (order in orders) {
        when (order.status) {
            Status.CANCELLED -> {
                println("PULAR: ${order.id} cancelado")
                continue@loop
            }
            else -> {
                val pipeline = routeOrder(order)
                val priority = if (order.total > 10_000) "CRITICAL" else "NORMAL"
                println("PROCESSAR: ${order.id} -> $pipeline [$priority]")
            }
        }
    }
}

fun main() {
    val orders = listOf(
        Order("ORD-001", 299.99, Status.CONFIRMED, "US"),
        Order("ORD-002", 15_000.00, Status.PENDING, "EU"),
        Order("ORD-003", 2_500.00, Status.CONFIRMED, "US"),
        Order("ORD-004", 45.50, Status.CANCELLED, "US"),
        Order("ORD-005", 800.00, Status.PENDING, "ASIA"),
        Order("ORD-006", 8_000.00, Status.SHIPPED, "US")
    )

    println("=== Roteamento de Pedidos ===")
    processBatch(orders)

    // Resumo usando resultados da expressão when
    val summary = orders
        .filter { it.status != Status.CANCELLED }
        .groupBy { routeOrder(it) }
        .mapValues { (pipeline, list) -> "${list.size} pedidos" }

    println("\n=== Resumo por Pipeline ===")
    summary.forEach { (pipeline, info) -> println("  $pipeline: $info") }
}

Saída:

TEXT 📖 Somente leitura
=== Roteamento de Pedidos ===
PROCESSAR: ORD-001 -> REGULAR_SHIPPING [NORMAL]
PROCESSAR: ORD-002 -> EU_COMPLIANCE_QUEUE [CRITICAL]
PROCESSAR: ORD-003 -> EXPRESS_SHIPPING [NORMAL]
PULAR: ORD-004 cancelado
PROCESSAR: ORD-005 -> STANDARD_QUEUE [NORMAL]
PROCESSAR: ORD-006 -> TRACKING_UPDATE [NORMAL]

=== Resumo por Pipeline ===
  REGULAR_SHIPPING: 1 pedidos
  EU_COMPLIANCE_QUEUE: 1 pedidos
  EXPRESS_SHIPPING: 1 pedidos
  STANDARD_QUEUE: 1 pedidos
  TRACKING_UPDATE: 1 pedidos

9. Exemplos práticos rápidos

▶ Exemplo: if como expressão

KOTLIN
// if como expressão pode ser atribuído diretamente
val a = 10
val b = 20
val max = if (a > b) a else b
println("Max: $max")

// if multi-ramo como expressão
val score = 85
val grade = if (score >= 90) "A"
           else if (score >= 80) "B"
           else if (score >= 70) "C"
           else "F"
println("Pontuação $score -> Nota $grade")

// Com blocos (última expressão é retornada)
val description = if (score >= 60) {
    val bonus = score / 10
    "Aprovado com bônus: $bonus"
} else {
    "Reprovado"
}
println(description)

Saída:

TEXT 📖 Somente leitura
Max: 20
Pontuação 85 -> Nota B
Aprovado com bônus: 8

▶ Exemplo: when como expressão com tipos

KOTLIN
// when como expressão - força exaustividade
fun describe(value: Any): String = when (value) {
    is String -> "Texto com comprimento ${value.length}: \"$value\""
    is Int -> when {
        value > 0 -> "Inteiro positivo"
        value < 0 -> "Inteiro negativo"
        else -> "Zero"
    }
    is List<*> -> "Lista com ${value.size} elementos"
    is Map<*, *> -> "Mapa com ${value.size} entradas"
    null -> "Valor nulo"
    else -> "Outro tipo: ${value::class.simpleName}"
}

println(describe("Olá"))
println(describe(42))
println(describe(-5))
println(describe(listOf(1, 2, 3)))
println(describe(null))
println(describe(3.14))

Saída:

TEXT 📖 Somente leitura
Texto com comprimento 3: "Olá"
Inteiro positivo
Inteiro negativo
Lista com 3 elementos
Valor nulo
Outro tipo: double

▶ Exemplo: when com intervalos e guardas

KOTLIN
fun classifyOrder(total: Double, status: String): String = when {
    status == "CANCELLED" -> "Cancelado - pular"
    total > 10_000 -> "VIP - prioridade máxima"
    total > 1_000 && status == "CONFIRMED" -> "Alta prioridade - envio rápido"
    total in 500.0..1_000.0 -> "Médio - processamento padrão"
    total < 0 -> "Erro - valor negativo"
    else -> "Padrão"
}

println(classifyOrder(15_000.0, "CONFIRMED"))
println(classifyOrder(2_500.0, "CONFIRMED"))
println(classifyOrder(750.0, "PENDING"))
println(classifyOrder(-100.0, "NEW"))
println(classifyOrder(50.0, "CANCELLED"))
println(classifyOrder(50.0, "NEW"))

Saída:

TEXT 📖 Somente leitura
VIP - prioridade máxima
Alta prioridade - envio rápido
Médio - processamento padrão
Erro - valor negativo
Cancelado - pular
Padrão

▶ Exemplo: for com intervalos e listas

KOTLIN
// Intervalo fechado
print("1..5: ")
for (i in 1..5) print("$i ")
println()

// Intervalo decrescente com step
print("10 downTo 1 step 2: ")
for (i in 10 downTo 1 step 2) print("$i ")
println()

// Semiaberto (até mas não incluindo)
print("0 until 5: ")
for (i in 0 until 5) print("$i ")
println()

// Lista
val fruits = listOf("maçã", "banana", "laranja")
for (fruit in fruits) println("Fruta: $fruit")

// Com índice
for ((index, fruit) in fruits.withIndex()) {
    println("$index: $fruit")
}

Saída:

TEXT 📖 Somente leitura
1..5: 1 2 3 4 5
10 downTo 1 step 2: 10 8 6 4 2
0 until 5: 0 1 2 3 4
Fruta: maçã
Fruta: banana
Fruta: laranja
0: maçã
1: banana
2: laranja

▶ Exemplo: while e do-while

KOTLIN
// while - verifica condição antes do loop
var countdown = 5
print("Contagem regressiva: ")
while (countdown > 0) {
    print("$countdown ")
    countdown--
}
println("Lançar!")

// do-while - executa pelo menos uma vez
var input = 0
var attempts = 0
do {
    attempts++
    input = (1..10).random()
    println("Tentativa $attempts: obteve $input")
} while (input < 5 && attempts < 5)
println("Final: $input após $attempts tentativas")

Saída:

TEXT 📖 Somente leitura
Contagem regressiva: 5 4 3 2 1 Lançar!
Tentativa 1: obteve 7
Final: 7 após 1 tentativas

▶ Exemplo: Rótulos em loops

KOTLIN
// Procurando em uma matriz 2D
val matrix = arrayOf(
    arrayOf(1, 2, 3),
    arrayOf(4, 5, 6),
    arrayOf(7, 8, 9)
)

var found = false
var targetValue = 5

outer@ for (i in matrix.indices) {
    inner@ for (j in matrix[i].indices) {
        if (matrix[i][j] == targetValue) {
            println("Encontrado $targetValue em [$i][$j]")
            found = true
            break@outer  // sai de ambos os loops
        }
    }
}

if (!found) println("$targetValue não encontrado")

// continue@label - pula para a próxima iteração de um loop específico
for (i in 1..5) {
    if (i == 3) continue
    print("$i ")
}

Saída:

TEXT 📖 Somente leitura
Encontrado 5 em [1][1]
1 2 4 5

▶ Exemplo: return@label em lambdas

KOTLIN
val orders = listOf(
    "ORD-001" to "CONFIRMED",
    "ORD-002" to "CANCELLED",
    "ORD-003" to "PENDING",
    "ORD-004" to "CONFIRMED"
)

// return@forEach pula apenas este elemento
orders.forEach { (id, status) ->
    if (status == "CANCELLED") {
        println("PULAR $id (cancelado)")
        return@forEach
    }
    println("PROCESSAR $id ($status)")
}

// Procurando primeiro elemento correspondente
val firstCancelled = orders.firstOrNull { it.second == "CANCELLED" }
println("Primeiro cancelado: ${firstCancelled?.first}")

// takeWhile / dropWhile
val pendingOrders = orders.takeWhile { it.second == "CONFIRMED" }
println("Take while CONFIRMED: $pendingOrders")

val remaining = orders.dropWhile { it.second == "CONFIRMED" }
println("Drop while CONFIRMED: $remaining")

Saída:

TEXT 📖 Somente leitura
PULAR ORD-002 (cancelado)
PROCESSAR ORD-001 (CONFIRMED)
PROCESSAR ORD-003 (PENDING)
PROCESSAR ORD-004 (CONFIRMED)
Primeiro cancelado: ORD-002
Take while CONFIRMED: [(ORD-001, CONFIRMED)]
Drop while CONFIRMED: [(ORD-002, CANCELLED), (ORD-003, PENDING), (ORD-004, CONFIRMED)]

❓ Perguntas Frequentes

P: O Kotlin tem um operador ternário ?:? R: Não. O Kotlin usa if/else em vez de um operador ternário porque if é uma expressão — funcionalmente equivalente e mais legível.

P: Qual a diferença entre when com e sem sujeito? R: when(x) corresponde ao valor/tipo de x com verificação de exaustividade pelo compilador; when { } são expressões condicionais arbitrárias e devem incluir else.

P: Um loop for pode iterar sobre objetos personalizados? R: Sim, desde que a classe implemente operator fun iterator() retornando um Iterator.

P: Quais são as limitações do retorno não local? R: O retorno não local só pode ser usado em lambdas de funções inline. Usar retorno não local em um lambda regular causa um erro de compilação.

P: A ordem dos ramos importa no when? R: Sim. when corresponde de cima para baixo, e o primeiro ramo satisfeito vence. Coloque condições mais específicas antes das mais gerais.

P: Como corresponder tanto um valor quanto uma condição no when? R: Use condições de guarda: is Order && total > 1000 -> — primeiro corresponde ao tipo, depois adiciona a condição.


📖 Resumo


📝 Exercícios

  1. Iniciante (⭐): Use expressões if para implementar uma função maxOfThree que retorna o máximo de três números. Dica: if aninhado ou use maxOf() da biblioteca padrão
  2. Intermediário (⭐⭐): Use when para implementar determinação de prioridade de pedido: VIP (>10000 USD) > Alta Prioridade (>1000) > Normal, pule pedidos cancelados. Dica: condições de guarda when
  3. Desafio (⭐⭐⭐): Use rótulos de loop para implementar processamento em lote de pedidos: loop externo sobre lotes de clientes, loop interno sobre pedidos — pule todo o lote do cliente se um pedido cancelado for encontrado. Dica: loop@ + continue@loop

← Anterior | Próximo →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%