Kotlin: Sintaxe Básica do Kotlin Explicada
Última atualização: 2026-08-26
A filosofia de sintaxe do Kotlin: use expressões em vez de instruções sempre que possível, e nunca escreva uma linha que não precise. Isso permite que Alice escreva código 40% mais curto que Java, expressando mais.
1. O que Você Aprenderá
valvsvar: a mentalidade de imutabilidade em primeiro lugar- Templates de string e strings brutas
- A expressão
whenem todas as suas formas - Intervalos e iteração:
../until/step/downTo - Funções de corpo de expressão e convenções idiomáticas
2. A História Real de um Desenvolvedor
(1) Problema: Estado Mutável Causa Bugs de Concorrência
Alice usou var para definir um contador de pedidos compartilhado no OrderProcessor. Sob alta concorrência, corridas de dados causaram um desvio de contagem de 2% — são 20.000 pedidos mal contados em escala.
(2) Solução: Imutabilidade em Primeiro Lugar
// RUIM: estado compartilhado mutável
var orderCount = 0 // Condição de corrida!
// BOM: imutável + pipeline funcional
val processedOrders = orders
.filter { it.status == "CONFIRMED" }
.also { println("Processados ${it.size} pedidos") }
Dados imutáveis são naturalmente seguros para threads.
valé a primeira escolha de todo desenvolvedor Kotlin;varé o último recurso.
3. val vs var: Imutabilidade em Primeiro Lugar
(1) Sintaxe Básica
// val: somente leitura (referência imutável) - PREFERIDO
val orderId = "ORD-001" // Tipo inferido como String
val total: Double = 299.99 // Tipo explícito
// var: mutável (reatribuível) - USE COM CUIDADO
var status = "PENDING" // Pode ser reatribuído
status = "CONFIRMED" // OK
// val NÃO significa que o objeto é imutável
val items = mutableListOf<Order>() // Referência é val, lista é mutável
items.add(Order("ORD-002", 150.0, "NEW")) // OK - modificando a lista
// items = mutableListOf() // ERRO - não pode reatribuir val
(2) Comparação val vs var
| Dimensão | val |
var |
|---|---|---|
| Reatribuível | Não | Sim |
| Segurança de thread | Referência imutável, naturalmente segura | Precisa de sincronização |
| Recomendação | Preferido | Último recurso |
| Análogo Java | final |
Variável regular |
| Por baixo dos panos | Referência somente leitura (objeto pode ser mutável) | Referência mutável |
4. Templates de String
(1) Templates Básicos
val orderId = "ORD-001"
val total = 299.99
// Referência simples de variável
println("Pedido: $orderId")
// Expressão no template
println("Total: \$$total USD")
println("Imposto: \$${total * 0.08} USD")
// Expressão arbitrária com ${}
val items = listOf("Widget", "Gadget")
println("Quantidade de itens: ${items.size}, Primeiro: ${items[0]}")
(2) Strings Brutas (Multilinha)
val receipt = """
|ID Pedido: ORD-001
|Total: $299.99 USD
|Status: CONFIRMED
""".trimMargin()
// Alternativa: trimIndent
val json = """
{
"order_id": "ORD-001",
"total": 299.99
}
""".trimIndent()
(3) Comparação de Templates de String
| Recurso | Java | Kotlin |
|---|---|---|
| Referência de variável | "Order " + id |
"Order $id" |
| Expressão | "Tax: " + (t * 0.08) |
"Tax: ${t * 0.08}" |
| Multilinha | Sem suporte nativo | """ ... """ |
| Tratamento de indentação | Manual | trimMargin() / trimIndent() |
5. Expressão when
when é a atualização completa do switch — é uma expressão com valor de retorno que pode corresponder a tipos, intervalos e condições arbitrárias.
(1) Uso Básico
// when como expressão (deve ser exaustivo)
val status = "CONFIRMED"
val label = when (status) {
"PENDING" -> "Aguardando pagamento"
"CONFIRMED" -> "Pagamento recebido"
"SHIPPED" -> "Em trânsito"
"CANCELLED" -> "Pedido cancelado"
else -> "Status desconhecido"
}
(2) Correspondência Avançada
// Múltiplos valores
when (status) {
"PENDING", "NEW" -> processNewOrder()
in listOf("CONFIRMED", "PAID") -> shipOrder()
else -> handleOther()
}
// Correspondência por intervalo
val quantity = 150
when (quantity) {
in 1..10 -> println("Pedido pequeno")
in 11..100 -> println("Pedido médio")
in 101..1_000 -> println("Pedido grande")
else -> println("Pedido em volume")
}
// Correspondência por tipo
fun describe(obj: Any): String = when (obj) {
is String -> "String de comprimento ${obj.length}"
is Int -> "Inteiro: $obj"
is List<*> -> "Lista com ${obj.size} elementos"
else -> "Tipo desconhecido"
}
(3) Árvore de Decisão do when
flowchart LR
A[when status] --> B["PENDING, NEW"]
A --> C["CONFIRMED, PAID"]
A --> D["SHIPPED"]
A --> E["CANCELLED"]
A --> F[else]
B --> B1[processNewOrder]
C --> C1[shipOrder]
D --> D1[trackShipment]
E --> E1[refundOrder]
F --> F1[handleOther]
(4) when vs switch
| Dimensão | Java switch | Kotlin when |
|---|---|---|
| Valor de retorno | Instrução, sem retorno | Expressão, retorna valor |
| Correspondência de múltiplos valores | Requer fall-through | "A", "B" separados por vírgula |
| Correspondência por intervalo | Não disponível | in 1..100 |
| Correspondência por tipo | Não disponível | is String |
| Condição de guarda | Não disponível | x > 0 arbitrária |
| Verificação de exaustividade | Nenhuma | Aplicada pelo compilador (modo expressão) |
6. Intervalos e Iteração
(1) Operadores de Intervalo
// Intervalo fechado: inclui ambos os extremos
for (i in 1..5) print("$i ") // 1 2 3 4 5
// Intervalo semiaberto: exclui o final
for (i in 1 until 5) print("$i ") // 1 2 3 4
// Passo
for (i in 1..10 step 2) print("$i ") // 1 3 5 7 9
// Decrescente
for (i in 5 downTo 1) print("$i ") // 5 4 3 2 1
// Intervalo de caracteres
for (c in 'A'..'E') print("$c ") // A B C D E
(2) Iteração de Coleções
val orders = listOf(
Order("ORD-001", 299.99),
Order("ORD-002", 1_500.00),
Order("ORD-003", 45.50)
)
// Iterar com índice
for ((index, order) in orders.withIndex()) {
println("[$index] ${order.id}: \$${order.total} USD")
}
// Iterar mapa
val statusMap = mapOf("ORD-001" to "SHIPPED", "ORD-002" to "PENDING")
for ((id, status) in statusMap) {
println("$id -> $status")
}
(3) Referência Rápida de Operadores de Intervalo
| Operador | Significado | Exemplo | Resultado |
|---|---|---|---|
.. |
Intervalo fechado | 1..5 |
1,2,3,4,5 |
until |
Intervalo semiaberto | 1 until 5 |
1,2,3,4 |
step |
Tamanho do passo | 1..10 step 3 |
1,4,7,10 |
downTo |
Decrescente | 5 downTo 1 |
5,4,3,2,1 |
in |
Verificação de pertencimento | 3 in 1..5 |
true |
7. Funções de Corpo de Expressão e Idiomas
(1) Funções de Corpo de Expressão
// Corpo de bloco
fun calculateTax(total: Double): Double {
return total * 0.08
}
// Corpo de expressão (mais conciso)
fun calculateTax(total: Double): Double = total * 0.08
// Inferência de tipo com corpo de expressão
fun calculateTax(total: Double) = total * 0.08
(2) Idiomas Kotlin
// 1. Ponto e vírgula é opcional
val x = 1 // Sem ponto e vírgula necessário
// 2. Convenção de lambda final
orders.filter { it.total > 1_000 } // lambda fora dos parênteses
// 3. Palavra-chave it para lambda de parâmetro único
orders.map { it.id } // 'it' = parâmetro implícito
// 4. Template de string em vez de concatenação
val msg = "Pedido $orderId confirmado" // Não "Pedido " + orderId + " confirmado"
// 5. Corpo de expressão para funções simples
fun isHighValue(order: Order) = order.total > 10_000
(3) Comparação de Idiomas: Java vs Kotlin
| Idioma | Java | Kotlin |
|---|---|---|
| Ponto e vírgula | Obrigatório | Opcional |
| Concatenação de string | Operador + |
Template $ |
| Funções simples | Corpo de bloco | Corpo de expressão |
| Posicionamento de lambda | Dentro dos parênteses | Final, fora dos parênteses |
| Lambda de parâmetro único | Parâmetro nomeado | Palavra-chave it |
8. Exemplo Completo: Roteamento de Pedidos do OrderProcessor
// ============================================
// OrderProcessor - Motor de Roteamento de Pedidos
// Funcionalidade: Rotear pedidos com base em status e valor
// ============================================
data class Order(val id: String, val total: Double, val status: String)
fun routeOrder(order: Order): String = when {
order.status == "CANCELLED" -> "REFUND_QUEUE"
order.total > 10_000 -> "VIP_PIPELINE"
order.total > 1_000 -> "PRIORITY_PIPELINE"
order.status == "CONFIRMED" -> "STANDARD_PIPELINE"
order.status in listOf("PENDING", "NEW") -> "WAITING_QUEUE"
else -> "MANUAL_REVIEW"
}
fun processBatch(orders: List<Order>) {
for ((index, order) in orders.withIndex()) {
val pipeline = routeOrder(order)
val priority = when (pipeline) {
"VIP_PIPELINE" -> "CRITICAL"
"PRIORITY_PIPELINE" -> "HIGH"
"STANDARD_PIPELINE" -> "NORMAL"
else -> "LOW"
}
println("[${index + 1}] ${order.id} -> $pipeline (Prioridade: $priority)")
}
}
fun main() {
val orders = listOf(
Order("ORD-001", 299.99, "CONFIRMED"),
Order("ORD-002", 15_000.00, "CONFIRMED"),
Order("ORD-003", 2_500.00, "PENDING"),
Order("ORD-004", 45.50, "CANCELLED"),
Order("ORD-005", 750.00, "NEW")
)
println("=== Relatório de Roteamento de Pedidos ===")
processBatch(orders)
// Resumo com pipeline funcional
val pipelineCounts = orders
.map { routeOrder(it) }
.groupingBy { it }
.eachCount()
println("\n=== Distribuição por Pipeline ===")
for ((pipeline, count) in pipelineCounts) {
println(" $pipeline: $count pedidos")
}
}
Saída:
=== Relatório de Roteamento de Pedidos ===
[1] ORD-001 -> STANDARD_PIPELINE (Prioridade: NORMAL)
[2] ORD-002 -> VIP_PIPELINE (Prioridade: CRITICAL)
[3] ORD-003 -> PRIORITY_PIPELINE (Prioridade: HIGH)
[4] ORD-004 -> REFUND_QUEUE (Prioridade: LOW)
[5] ORD-005 -> WAITING_QUEUE (Prioridade: LOW)
=== Distribuição por Pipeline ===
STANDARD_PIPELINE: 1 pedidos
VIP_PIPELINE: 1 pedidos
PRIORITY_PIPELINE: 1 pedidos
REFUND_QUEUE: 1 pedidos
WAITING_QUEUE: 1 pedidos
❓ Perguntas Frequentes
P: Posso modificar o conteúdo de uma coleção val? R: Sim. val apenas garante que a referência é imutável — o conteúdo da coleção ainda pode mudar. Para coleções verdadeiramente imutáveis, use
listOf()em vez demutableListOf().
P: when sempre requer else? R: Quando
whené usado como expressão, o compilador exige exaustividade — você deve cobrir todos os ramos ou adicionar else. Quando usado como instrução, else é opcional.
P:
1..5e1 until 6são iguais? R: Mesmo resultado, semântica diferente.1..5significa "de 1 até 5 inclusive",1 until 6significa "de 1 até (mas não incluindo) 6". Ao iterar índices de lista,untilé mais comum.
P: Quando devo usar funções de corpo de expressão? R: Use corpos de expressão quando a função é uma única expressão. Use corpos de bloco para qualquer coisa com 2+ linhas de lógica. Legibilidade é a prioridade principal.
P: Qual a diferença entre
$vare${expr}nos templates de string? R:$varsó pode referenciar nomes simples de variáveis;${expr}pode conter qualquer expressão, como${items.size}ou${total * 0.08}.
P: when pode corresponder a intervalos de ponto flutuante? R: Tecnicamente sim, mas problemas de precisão de ponto flutuante podem causar resultados inesperados. Prefira intervalos inteiros ou comparações explícitas.
▶ Exemplo: val vs var
val name = "Alice" // imutável
var age = 30 // mutável
age = 31 // OK
// name = "Bob" // erro de compilação
Saída:
Compila; reatribuir name falha
▶ Exemplo: Expressão when
val score = 85
val grade = when {
score >= 90 -> "A"
score >= 80 -> "B"
else -> "C"
}
println(grade)
Saída:
B
▶ Exemplo: Loop for
for (i in 1..3) println(i)
for (s in listOf("a", "b")) println(s)
Saída:
1
2
3
a
b
▶ Exemplo: Template de string multilinha
val name = "Alice"
val orders = 1500
val revenue = 89500.50
val summary = """
|== Relatório do Usuário ==
| Nome : $name
| Pedidos : $orders
| Receita : \$${revenue} USD
| Média : \$${revenue / orders} USD
|================
""".trimMargin()
println(summary)
Saída:
|== Relatório do Usuário ==
| Nome : Alice
| Pedidos : 1500
| Receita : $89500.5 USD
| Média : $59.66699999999999 USD
|================
▶ Exemplo: Intervalo com step e downTo
// Intervalo crescente com step
for (i in 1..10 step 2) print("$i ")
println()
// Intervalo decrescente
for (i in 5 downTo 1) print("$i ")
println()
// Semiaberto com until
for (i in 0 until 5) print("$i ")
Saída:
1 3 5 7 9
5 4 3 2 1
0 1 2 3 4
▶ Exemplo: Função de corpo de expressão
// Corpo de bloco - múltiplas linhas
fun describeOrder(status: String): String {
return when (status) {
"CONFIRMED" -> "Confirmado"
"SHIPPED" -> "Enviado"
"DELIVERED" -> "Entregue"
"CANCELLED" -> "Cancelado"
else -> "Desconhecido"
}
}
// Corpo de expressão - uma linha
fun isVip(total: Double) = total > 10_000
// Função sem valor de retorno (Unit)
fun logOrder(id: String): Unit = println("Registrado: $id")
println(describeOrder("CONFIRMED"))
println("VIP: ${isVip(15_000.0)}")
logOrder("ORD-001")
Saída:
Confirmado
VIP: true
Registrado: ORD-001
▶ Exemplo: Null safety com when
fun describeValue(v: Any?): String = when (v) {
null -> "Valor nulo"
is String -> "Texto com comprimento ${v.length}: \"$v\""
is Int -> if (v > 0) "Inteiro positivo" else "Inteiro não positivo"
is List<*> -> "Lista com ${v.size} elementos"
is Map<*, *> -> "Mapa com ${v.size} entradas"
else -> "Outro tipo: ${v::class.simpleName}"
}
println(describeValue(null))
println(describeValue("olá"))
println(describeValue(42))
println(describeValue(listOf(1, 2, 3)))
println(describeValue(3.14))
Saída:
Valor nulo
Texto com comprimento 3: "olá"
Inteiro positivo
Lista com 3 elementos
Outro tipo: double
📖 Resumo
valprimeiro,varpor último — referências imutáveis são naturalmente seguras para threads- Templates de string com
$/${}substituem concatenação de strings;"""para multilinha whené a atualização expressiva doswitch: correspondência de múltiplos valores, intervalos, tipos e guardas- Operadores de intervalo:
..(fechado),until(semiaberto),step,downTo - Funções de corpo de expressão tornam funções simples concisas; legibilidade decide o compromisso
- Idiomas Kotlin: sem ponto e vírgula, lambdas finais, palavra-chave
it, templates de string
📝 Exercícios
- Iniciante (⭐) : Escreva uma função usando
vale templates de string que produza um resumo de pedido"ORD-001: $299.99 USD (CONFIRMED)". Dica:val id = "ORD-001",val total = 299.99 - Intermediário (⭐⭐) : Implemente uma calculadora de desconto com
when: > 10.000 → 20% de desconto, > 5.000 → 10% de desconto, caso contrário preço integral. Dica: condições de guardawhen {} - Desafio (⭐⭐⭐) : Implemente uma calculadora de imposto progressivo usando intervalos e
when. Diferentes faixas de renda aplicam diferentes taxas de imposto. Dica:when { income in range -> ... }