---
title: "Property Delegate em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/property-delegate/"
markdown_url: "https://kotlin.dev.br/glossario/property-delegate.MD"
description: "Aprenda o que são Property Delegates em Kotlin, como delegar lógica de leitura e escrita de propriedades."
date: "2025-08-16"
author: "Karina Melo"
---

# Property Delegate em Kotlin: O que É e Como Funciona | Kotlin Brasil

Aprenda o que são Property Delegates em Kotlin, como delegar lógica de leitura e escrita de propriedades.


## O que é Property Delegate em Kotlin?

**Property Delegate** (delegação de propriedade) é um mecanismo do Kotlin que permite **delegar a lógica de leitura (get) e escrita (set) de uma propriedade para outro objeto**. Em vez de implementar a lógica diretamente na propriedade, você usa a palavra-chave `by` para apontar para um objeto delegado que controla o comportamento.

Os delegates mais conhecidos da biblioteca padrão são `lazy`, `observable` e `vetoable`, mas você pode criar os seus próprios para qualquer necessidade.

### Sintaxe básica

```kotlin
class Exemplo {
    // Delegando para lazy: inicializa na primeira leitura
    val configuracao: String by lazy {
        println("Calculando...")
        "Valor configurado"
    }
}

fun main() {
    val obj = Exemplo()
    println(obj.configuracao) // Imprime "Calculando..." e "Valor configurado"
    println(obj.configuracao) // Imprime apenas "Valor configurado" (ja calculado)
}
```

A palavra-chave `by` indica que a propriedade esta delegando suas operações de get (e set, se for `var`) para o objeto a direita.

### Como funciona internamente

Quando você escreve `val x by delegate`, o compilador gera código equivalente a:

```kotlin
// Você escreve:
class Exemplo {
    val x: String by MeuDelegate()
}

// O compilador gera algo como:
class Exemplo {
    private val x_delegate = MeuDelegate()

    val x: String
        get() = x_delegate.getValue(this, ::x)
}
```

Para propriedades `var`, o compilador também gera o setter:

```kotlin
// var y by delegate gera:
var y: String
    get() = y_delegate.getValue(this, ::y)
    set(value) { y_delegate.setValue(this, ::y, value) }
```

### Delegates da biblioteca padrão

#### lazy

Inicializa o valor na primeira leitura e cacheia para acessos subsequentes:

```kotlin
val dadosPesados: List<String> by lazy {
    println("Carregando dados pesados...")
    carregarDoBanco()
}
```

Modos de thread safety do lazy:

```kotlin
// Thread-safe (padrao): sincronizado
val a by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { calcular() }

// Sem sincronizacao: mais rapido, mas nao thread-safe
val b by lazy(LazyThreadSafetyMode.NONE) { calcular() }

// Publication: permite calculo duplicado, mas garante que todos veem o mesmo valor
val c by lazy(LazyThreadSafetyMode.PUBLICATION) { calcular() }
```

#### observable

Notifica quando o valor muda:

```kotlin
import kotlin.properties.Delegates

var nome: String by Delegates.observable("Inicial") { propriedade, valorAntigo, valorNovo ->
    println("${propriedade.name} mudou de '$valorAntigo' para '$valorNovo'")
}

fun main() {
    nome = "Ana"    // Imprime: nome mudou de 'Inicial' para 'Ana'
    nome = "Bruno"  // Imprime: nome mudou de 'Ana' para 'Bruno'
}
```

#### vetoable

Permite rejeitar mudancas de valor:

```kotlin
var idade: Int by Delegates.vetoable(0) { _, _, novoValor ->
    novoValor >= 0 // So aceita valores nao-negativos
}

fun main() {
    idade = 25   // Aceito
    println(idade) // 25
    idade = -5   // Rejeitado
    println(idade) // 25 (nao mudou)
}
```

#### notNull

Similar ao `lateinit`, mas funciona com tipos primitivos delegados:

```kotlin
var contador: Int by Delegates.notNull<Int>()

fun main() {
    // println(contador) // IllegalStateException!
    contador = 42
    println(contador)  // 42
}
```

### Criando um delegate customizado

Para criar um delegate, implemente os operadores `getValue` e opcionalmente `setValue`:

```kotlin
import kotlin.reflect.KProperty

class LoggingDelegate<T>(private var valor: T) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        println("Lendo ${property.name}: $valor")
        return valor
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, novoValor: T) {
        println("Escrevendo ${property.name}: $valor -> $novoValor")
        valor = novoValor
    }
}

class Usuario {
    var nome: String by LoggingDelegate("Sem nome")
    var idade: Int by LoggingDelegate(0)
}

fun main() {
    val u = Usuario()
    u.nome = "Ana"     // Escrevendo nome: Sem nome -> Ana
    println(u.nome)    // Lendo nome: Ana
    u.idade = 30       // Escrevendo idade: 0 -> 30
}
```

### Exemplo prático: SharedPreferences delegate

Um caso de uso real no Android e delegar propriedades para SharedPreferences:

```kotlin
class PreferenceDelegate(
    private val prefs: SharedPreferences,
    private val chave: String,
    private val padrao: String
) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return prefs.getString(chave, padrao) ?: padrao
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, valor: String) {
        prefs.edit().putString(chave, valor).apply()
    }
}

fun SharedPreferences.string(chave: String, padrao: String = "") =
    PreferenceDelegate(this, chave, padrao)

// Uso
class Configurações(prefs: SharedPreferences) {
    var tema: String by prefs.string("tema", "claro")
    var idioma: String by prefs.string("idioma", "pt-BR")
    var nomeUsuario: String by prefs.string("nome_usuario", "")
}

fun main() {
    val config = Configurações(obterPrefs())
    config.tema = "escuro"           // Salva automaticamente no SharedPreferences
    println(config.tema)             // Le automaticamente do SharedPreferences
}
```

### Delegate para Map

Kotlin tem suporte embutido para delegar propriedades a um `Map`:

```kotlin
class Usuario(mapa: Map<String, Any?>) {
    val nome: String by mapa
    val idade: Int by mapa
    val email: String by mapa
}

fun main() {
    val dados = mapOf(
        "nome" to "Ana",
        "idade" to 30,
        "email" to "ana@email.com"
    )
    val usuario = Usuario(dados)
    println(usuario.nome)  // Ana
    println(usuario.idade) // 30
}
```

Para propriedades mutaveis, use `MutableMap`:

```kotlin
class Configuração(mapa: MutableMap<String, Any?>) {
    var tema: String by mapa
    var fontSize: Int by mapa
}
```

### Interfaces ReadOnlyProperty e ReadWriteProperty

Para maior clareza, seus delegates podem implementar interfaces oficiais:

```kotlin
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class ValidatedString(private var valor: String) : ReadWriteProperty<Any?, String> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): String = valor

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        require(value.isNotBlank()) { "${property.name} nao pode ser vazio" }
        valor = value
    }
}

class Formulario {
    var nome: String by ValidatedString("")
    var email: String by ValidatedString("")
}
```

### Quando usar Property Delegates

- **Inicialização preguicosa**: `lazy` para valores calculados sob demanda.
- **Observacao de mudancas**: `observable` e `vetoable` para reagir a alteracoes de estado.
- **Persistencia transparente**: delegar para SharedPreferences, banco de dados ou cache.
- **Validação automatica**: verificar restricoes a cada escrita sem repetir código.
- **Logging e auditoria**: registrar acessos e modificacoes de propriedades.

### Casos de Uso no Mundo Real

1. **Persistencia transparente em Android**: delegates que encapsulam SharedPreferences ou DataStore permitem que propriedades de uma classe de configuração leiam e escrevam automaticamente no armazenamento persistente. O desenvolvedor interage com a propriedade como se fosse um campo normal, sem se preocupar com a camada de persistencia.

2. **Injecao de dependência em frameworks como Koin**: o Koin usa property delegates (`by inject()` e `by viewModel()`) para injetar dependências de forma preguicosa em Activities, Fragments e ViewModels. Isso elimina boilerplate de resolucao manual e torna o código mais declarativo.

3. **Binding de views em Android legado**: antes do Jetpack Compose, bibliotecas como ViewBinding e ButterKnife usavam delegates para vincular views do XML a propriedades da Activity ou Fragment, evitando chamadas repetidas a `findViewById`.

4. **Validacao e sanitizacao automatica de dados**: em sistemas de formularios ou APIs, delegates customizados podem validar valores a cada escrita (rejeitando dados invalidos) ou sanitizar entradas (removendo espacos extras, normalizando formatos) de forma transparente para o restante do código.

### Boas Praticas

- **Use `lazy` com o modo de thread safety adequado**: em contextos single-thread (como a thread principal do Android), use `LazyThreadSafetyMode.NONE` para evitar o overhead de sincronizacao desnecessaria.
- **Implemente as interfaces `ReadOnlyProperty` ou `ReadWriteProperty`**: ao criar delegates customizados, implementar essas interfaces torna o contrato explicito e facilita a leitura e manutenção do código.
- **Evite efeitos colaterais pesados em `getValue`**: o getter de uma propriedade delegada e chamado toda vez que a propriedade e lida. operações caras (como acesso a disco ou rede) devem ser cacheadas internamente pelo delegate.
- **Prefira delegates a campos com lógica duplicada**: se você perceber que várias propriedades da mesma classe possuem lógica identica de validacao, logging ou persistencia, extraia essa lógica para um delegate reutilizavel.
- **Documente delegates customizados com exemplos de uso**: como delegates alteram o comportamento implicito de propriedades, outros desenvolvedores precisam entender o que acontece por tras do `by`. Um KDoc com exemplo e essencial.

### Perguntas Frequentes

**P: Qual a diferenca entre `lazy` e `lateinit`?**
R: `lazy` e um delegate para propriedades `val` que inicializa o valor na primeira leitura e o cacheia. `lateinit` e um modificador para propriedades `var` que permite declarar a propriedade sem valor inicial, atribuindo-o depois. `lazy` garante que o valor e calculado exatamente uma vez; `lateinit` permite reatribuicao e não suporta tipos primitivos.

**P: Posso usar property delegates com propriedades de nivel de arquivo (top-level)?**
R: Sim. Property delegates funcionam em propriedades de classes, objetos, interfaces e também em propriedades top-level. Para propriedades top-level, o parametro `thisRef` do `getValue`/`setValue` sera `null`, já que não há um objeto proprietario.

**P: Como faco para delegar uma propriedade a outra propriedade da mesma classe?**
R: A partir do Kotlin 1.4, você pode usar a sintaxe `val novoNome by ::nomeAntigo` para delegar uma propriedade a outra usando referência de propriedade. Isso e útil para renomear propriedades mantendo compatibilidade com código existente.

**P: Property delegates impactam a performance da aplicação?**
R: O impacto e minimo para a maioria dos casos. O delegate adiciona uma camada de indirection (uma chamada de método extra para `getValue`/`setValue`), mas o JIT do JVM normalmente otimiza isso. O `lazy` com `SYNCHRONIZED` tem um custo de sincronizacao na primeira leitura, mas leituras subsequentes sao rapidas.

### Erros comuns

1. **Nao entender que lazy e thread-safe por padrão**: o modo `SYNCHRONIZED` tem overhead. Use `NONE` quando thread safety não e necessária.

2. **Criar delegates com efeitos colaterais pesados no getValue**: o getter e chamado toda vez que a propriedade e lida. Operações caras devem ser cacheadas.

3. **Esquecer de implementar setValue para var**: se o delegate não tem `setValue`, ele só funciona com `val`.

4. **Confundir delegação de propriedade com delegação de classe**: `class A by b` delega a interface de uma classe; `val x by delegate` delega uma propriedade. São mecanismos diferentes.

5. **Usar lazy em propriedades que mudam**: `lazy` e para `val`. Se você precisa de inicialização tardia com `var`, use `lateinit` ou `Delegates.notNull`.

### Termos relacionados

- **lazy**: delegate da biblioteca padrão para inicialização preguicosa.
- **lateinit**: alternativa ao delegate `notNull` para inicialização tardia.
- **Delegation**: conceito mais amplo que inclui delegação de classes e interfaces.
- **observable/vetoable**: delegates para monitorar e controlar mudancas de valor.
- **val/var**: delegates para `val` precisam apenas de `getValue`; delegates para `var` precisam também de `setValue`.
- **KProperty**: objeto de reflexao que representa a propriedade sendo delegada.

Property Delegates são um dos recursos mais elegantes do Kotlin, permitindo separar a lógica transversal (logging, persistencia, válidação) da lógica de negócio de forma limpa e reutilizavel. Dominar esse conceito abre portas para APIs expressivas e código sem boilerplate.
