Qual a diferença entre val e var em Kotlin?

Essa é uma das primeiras coisas que você aprende em Kotlin, e entender direitinho a diferença entre val e var vai te poupar muita dor de cabeça. Vamos lá!

A explicação rápida

  • val (de value): declara uma variável imutável. Depois que você atribui um valor, não pode mais mudar.
  • var (de variable): declara uma variável mutável. Você pode alterar o valor quantas vezes quiser.

Pense assim: val é como escrever a caneta, e var é como escrever a lápis.

Se você quer se aprofundar nesses conceitos, temos páginas dedicadas no glossário para val e var, além de um tutorial completo sobre variáveis e tipos em Kotlin.

Na prática

fun main() {
    // val - imutável: uma vez atribuído, não muda
    val nome = "Karina"
    // nome = "Ana"  // ERRO! Não pode reatribuir um val

    // var - mutável: pode mudar à vontade
    var pontuacao = 0
    println("Pontuação inicial: $pontuacao")

    pontuacao = 10
    println("Pontuação atualizada: $pontuacao")

    pontuacao += 5
    println("Pontuação final: $pontuacao")
}

Se você tentar reatribuir um val, o compilador vai reclamar na hora com um erro bem claro. Isso é uma mão na roda pra evitar bugs.

Quando usar cada um?

A regra de ouro é: prefira sempre val. Use var somente quando realmente precisar alterar o valor depois.

Por que? Variáveis imutáveis tornam o código mais previsível e seguro. Quando você sabe que um valor não vai mudar, fica muito mais fácil entender o que o código está fazendo.

fun main() {
    // Boas práticas
    val cpf = "123.456.789-00"          // CPF não muda, usa val
    val dataNascimento = "15/03/1995"   // data de nascimento não muda, usa val
    var saldo = 1000.0                   // saldo muda, usa var

    saldo -= 150.0  // compra no débito
    println("Saldo atual: R$ $saldo")
}

Cuidado: val não significa objeto imutável

Um detalhe que pega muita gente: val impede a reatribuição, mas não impede a modificação interna do objeto. Veja:

fun main() {
    val frutas = mutableListOf("Banana", "Maçã", "Manga")

    // Isso funciona! Estamos modificando a lista, não reatribuindo a variável
    frutas.add("Abacaxi")
    println(frutas) // [Banana, Maçã, Manga, Abacaxi]

    // Isso NÃO funciona! Estamos tentando reatribuir
    // frutas = mutableListOf("Uva")  // ERRO!
}

Se quiser uma lista que não pode ser modificada de jeito nenhum, use listOf() em vez de mutableListOf(). Para entender melhor as diferenças entre coleções mutáveis e imutáveis, confira nosso conteúdo sobre collections e o tutorial de coleções em Kotlin.

Erros comuns de quem está começando

Vamos ver alguns erros que aparecem com frequência e como evitá-los:

1. Usar var quando val resolveria

// Ruim: var desnecessário
var mensagem = "Bem-vindo ao sistema"
println(mensagem)

// Bom: se não vai mudar, use val
val mensagem = "Bem-vindo ao sistema"
println(mensagem)

O IntelliJ IDEA e o Android Studio inclusive exibem um aviso quando você declara um var que nunca é reatribuído, sugerindo trocar para val.

2. Confundir imutabilidade da referência com imutabilidade do conteúdo

fun main() {
    val numeros = mutableListOf(1, 2, 3)
    numeros.add(4)       // Funciona: estamos alterando o conteúdo
    // numeros = mutableListOf(5)  // ERRO: estamos tentando reatribuir a referência

    // Para imutabilidade total, combine val com coleção imutável
    val numerosFixos = listOf(1, 2, 3)
    // numerosFixos.add(4)  // ERRO: listOf() não tem método add
}

3. Esquecer que val funciona diferente em classes

Dentro de uma classe, val define uma propriedade somente leitura, enquanto var define uma propriedade que pode ser alterada:

class ContaBancaria(val titular: String, var saldo: Double) {
    fun depositar(valor: Double) {
        saldo += valor  // OK: saldo é var
    }

    // titular não pode ser alterado depois da criação
}

fun main() {
    val conta = ContaBancaria("Maria", 500.0)
    conta.depositar(200.0)
    println("Saldo: ${conta.saldo}") // 700.0
    // conta.titular = "Joao"  // ERRO! titular é val
}

val e var em funções

Parâmetros de funções em Kotlin são sempre imutáveis (equivalentes a val). Você não pode reatribuir um parâmetro dentro do corpo da função:

fun calcularDesconto(preco: Double, percentual: Double): Double {
    // preco = preco * 0.9  // ERRO! Parâmetros são imutáveis
    val precoComDesconto = preco * (1 - percentual / 100)
    return precoComDesconto
}

Essa decisão de design foi intencional. Ela evita efeitos colaterais confusos e torna o código mais previsível. Se você vem do Java, onde parâmetros podem ser reatribuídos, vai notar essa diferença logo de cara.

val e var com delegação de propriedades

Kotlin tem um recurso avançado chamado delegação de propriedades que funciona tanto com val quanto com var. O exemplo mais conhecido é o lazy, que só inicializa o valor quando ele é acessado pela primeira vez:

val configuracao: Map<String, String> by lazy {
    println("Carregando configuração...")
    mapOf("tema" to "escuro", "idioma" to "pt-BR")
}

fun main() {
    println("Antes de acessar")
    println(configuracao["tema"]) // Só aqui o bloco lazy é executado
}

Para saber mais sobre esse recurso, veja nosso glossário sobre property delegate.

Resumindo

Aspectovalvar
ReatribuiçãoNão permitePermite
Equivalente em Javafinalvariável comum
Quando usarSempre que possívelQuando precisar mudar o valor
Parâmetros de funçãoComportamento padrãoNão disponível
PerformancePode ser otimizado pelo compiladorSem otimizações extras

Adotar o hábito de usar val por padrão é uma das melhores práticas em Kotlin. Seu código fica mais limpo, mais seguro e mais fácil de manter. Na dúvida, comece com val e só troque pra var se o compilador reclamar que você está tentando alterar o valor.

Se você quer continuar aprendendo sobre os fundamentos da linguagem, confira nosso guia completo de Kotlin e o tutorial sobre funções em Kotlin. Para entender o conceito mais amplo de imutabilidade e por que ele é tão importante na programação moderna, temos um artigo dedicado no glossário.