---
title: "Noinline em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/noinline/"
markdown_url: "https://kotlin.dev.br/glossario/noinline.MD"
description: "Saiba o que é noinline em Kotlin, como impedir o inline de lambdas específicas em funções inline para mais flexibilidade."
date: "2025-08-15"
author: "Karina Melo"
---

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

Saiba o que é noinline em Kotlin, como impedir o inline de lambdas específicas em funções inline para mais flexibilidade.


## O que é noinline em Kotlin?

O modificador **`noinline`** é usado em parametros lambda de funções `inline` para indicar que **aquela lambda específica não deve ser inlineada**. Quando uma função e marcada como `inline`, por padrão todas as lambdas passadas a ela são copiadas no local da chamada. O `noinline` desativa esse comportamento para um parametro específico, tratando a lambda como um objeto `Function` normal.

Isso e necessário quando você precisa armazenar a lambda em uma variavel, passa-la para outra função não-inline ou usa-la como referência.

### Por que noinline existe?

Quando uma lambda e inlineada, ela não existe como objeto em tempo de execução -- seu código e copiado diretamente. Isso significa que você não pode:

- Armazena-la em uma variavel ou propriedade.
- Passa-la como argumento para funções não-inline.
- Obter uma referência a ela.

```kotlin
// ERRO: nao compila
inline fun problema(acao: () -> Unit) {
    val referência = acao  // Erro! Lambda inline nao pode ser armazenada
    executarDepois(acao)   // Erro! Nao pode passar para funcao nao-inline
}

fun executarDepois(acao: () -> Unit) {
    // ...
}
```

A solução e marcar a lambda como `noinline`:

```kotlin
inline fun funciona(noinline acao: () -> Unit) {
    val referência = acao     // OK
    executarDepois(referência) // OK
}
```

### Sintaxe e uso

```kotlin
inline fun processar(
    inlineada: () -> Unit,          // Sera inlineada normalmente
    noinline armazenavel: () -> Unit // Nao sera inlineada
) {
    inlineada()  // Código copiado no local da chamada

    // armazenavel pode ser tratada como objeto
    val lista = listOf(armazenavel)
    lista.forEach { it() }
}
```

### Exemplo prático: sistema de callbacks registrados

```kotlin
class GerenciadorDeEventos {
    private val callbacks = mutableListOf<() -> Unit>()

    // inline para a lambda de configuracao, noinline para o callback
    inline fun registrar(
        configurar: () -> Unit,
        noinline callback: () -> Unit
    ) {
        configurar()  // Inlineada: sem overhead de objeto
        callbacks.add(callback)  // Noinline: pode ser armazenada
    }

    fun dispararTodos() {
        callbacks.forEach { it() }
    }
}

fun main() {
    val gerenciador = GerenciadorDeEventos()

    gerenciador.registrar(
        configurar = { println("Configurando evento...") },
        callback = { println("Evento disparado!") }
    )

    gerenciador.dispararTodos()
}
```

Nesse exemplo, a lambda `configurar` e executada imediatamente e se beneficia do inline (sem alocacao de objeto). Ja o `callback` precisa ser armazenado para execução posterior, entao deve ser `noinline`.

### noinline vs crossinline

Ambos modificam o comportamento de lambdas em funções inline, mas de maneiras diferentes:

```kotlin
inline fun comparação(
    noinline lambdaNo: () -> Unit,       // NAO inlineada, vira objeto Function
    crossinline lambdaCross: () -> Unit  // Inlineada, mas sem non-local return
) {
    // noinline: pode ser armazenada como referência
    val ref: () -> Unit = lambdaNo  // OK
    // val ref2: () -> Unit = lambdaCross  // ERRO! crossinline ainda e inline

    // crossinline: pode ser usada em outro contexto
    val runnable = Runnable { lambdaCross() }  // OK
    // noinline tambem pode, mas sem beneficio de inline

    // noinline: non-local return NAO e possivel (e um objeto normal)
    // crossinline: non-local return NAO e possivel (proibido pelo crossinline)
    // inline normal: non-local return E possivel
}
```

Resumo:
| Caracteristica | inline | noinline | crossinline |
|---|---|---|---|
| Código copiado? | Sim | Nao | Sim |
| Non-local return? | Sim | Nao | Nao |
| Pode armazenar? | Nao | Sim | Nao |
| Overhead de objeto? | Nao | Sim | Nao |

### Quando noinline faz mais sentido que crossinline

```kotlin
// Use noinline quando precisa ARMAZENAR a lambda
class Cache<T> {
    private var provider: (() -> T)? = null

    inline fun configurar(noinline provider: () -> T) {
        this.provider = provider  // Precisa armazenar
    }

    fun obter(): T = provider?.invoke()
        ?: throw IllegalStateException("Provider nao configurado")
}

// Use crossinline quando precisa EXECUTAR em outro contexto sem armazenar
inline fun executarEmBackground(crossinline bloco: () -> Unit) {
    Thread { bloco() }.start()  // Executa, nao armazena
}
```

### Impacto na performance

A diferenca de performance entre lambdas inline e noinline e a alocacao de objetos:

```kotlin
inline fun comNoinline(noinline acao: () -> Unit) {
    acao()  // Chama como objeto Function: cria instancia no heap
}

inline fun semNoinline(acao: () -> Unit) {
    acao()  // Código copiado diretamente: sem alocacao
}

fun main() {
    // Com noinline: alocacao de objeto Function a cada chamada
    repeat(1_000_000) {
        comNoinline { /* trabalho */ }
    }

    // Sem noinline: nenhuma alocacao extra
    repeat(1_000_000) {
        semNoinline { /* trabalho */ }
    }
}
```

Em loops apertados com milhoes de iteracoes, a diferenca pode ser significativa. Porem, para a maioria do código de aplicação, o impacto e negligenciavel.

### Multiplas lambdas: inline seletivo

Uma função inline pode ter algumas lambdas inline e outras noinline:

```kotlin
inline fun <T> buscarComFallback(
    buscar: () -> T?,                    // Inlineada: executada diretamente
    noinline fallback: () -> T,          // Noinline: pode ser armazenada
    noinline onErro: (Exception) -> Unit // Noinline: pode ser passada adiante
) : T {
    return try {
        buscar() ?: fallback()
    } catch (e: Exception) {
        onErro(e)
        fallback()
    }
}
```

### Quando usar noinline

- **Armazenar lambdas**: quando a lambda precisa ser salva em uma propriedade, lista ou mapa para uso posterior.
- **Passar para funções não-inline**: quando a lambda sera argumento de outra função que não e inline.
- **Retornar lambdas**: quando uma função inline precisa retornar uma das lambdas recebidas.
- **Coleções de callbacks**: quando você gerencia uma lista de callbacks que serao executados depois.

### Casos de Uso no Mundo Real

1. **Sistemas de eventos e callbacks**: em frameworks de UI como Jetpack Compose ou sistemas de mensageria, funções inline frequentemente recebem lambdas que precisam ser armazenadas em listas de listeners para execução futura. O `noinline` permite que essas lambdas sejam registradas enquanto outras lambdas da mesma função continuam sendo inlineadas para performance.

2. **Frameworks de injecao de dependência**: bibliotecas como Koin usam funções inline com parametros `reified` para resolver tipos genericos, mas precisam armazenar factories (lambdas) em registros internos. O `noinline` e usado nos parametros de factory para que possam ser guardados em mapas de definicoes.

3. **Pipelines de processamento de dados**: ao construir pipelines funcionais onde algumas transformacoes sao executadas imediatamente (inline) e outras sao armazenadas para execução condicional ou adiada, o `noinline` permite misturar os dois comportamentos na mesma função.

4. **Logging e monitoramento em bibliotecas de alta performance**: funções utilitarias inline podem receber uma lambda de acao (inlineada para performance em hot paths) e uma lambda `noinline` de fallback ou erro que sera passada para um sistema de monitoramento externo.

### Boas Praticas

- **Prefira `crossinline` quando não precisa armazenar a lambda**: se o objetivo e apenas impedir non-local return mas a lambda sera executada no mesmo escopo, `crossinline` mantém o beneficio de performance do inline.
- **Evite marcar todas as lambdas como `noinline`**: se todas as lambdas de uma função inline sao `noinline`, a função não deveria ser inline (a menos que use `reified`). O compilador emite um warning nesses casos.
- **Documente por que uma lambda e `noinline`**: como o `noinline` tem impacto em performance e semantica, adicione um comentario breve explicando a necessidade (armazenamento, passagem para função não-inline, etc.).
- **Minimize o número de lambdas `noinline` em funções inline de hot path**: cada lambda `noinline` aloca um objeto `Function` no heap. Em loops com milhoes de iteracoes, prefira redesenhar a API para reduzir alocacoes.
- **Teste o comportamento de non-local return**: lembre-se de que lambdas `noinline` não suportam non-local return. Garanta que os chamadores da sua função não dependam desse comportamento.

### Perguntas Frequentes

**P: Posso usar `noinline` em uma função que não e `inline`?**
R: Nao. O modificador `noinline` só faz sentido em parametros lambda de funções marcadas como `inline`. Em funções normais, todas as lambdas já sao tratadas como objetos `Function`, entao `noinline` seria redundante e o compilador emite um erro.

**P: Qual o impacto real de performance do `noinline` em relacao ao `inline`?**
R: Cada chamada com lambda `noinline` aloca um objeto `Function` no heap, que posteriormente precisa ser coletado pelo garbage collector. Em código de aplicação comum, o impacto e negligenciavel. Porem, em hot paths com milhoes de iteracoes por segundo, a diferenca pode ser mensuravel em termos de pressao no GC e uso de memória.

**P: E possível ter uma função inline onde todas as lambdas sao `noinline`?**
R: Sim, o código compila, mas o compilador emite um warning indicando que não há beneficio em marcar a função como `inline` se nenhuma lambda e inlineada. A exceção e quando a função usa parametros de tipo `reified`, que exigem que a função seja inline.

**P: O `noinline` afeta o comportamento de `return` dentro da lambda?**
R: Sim. Uma lambda `noinline` se comporta como uma lambda normal: você só pode usar `return` qualificado (por exemplo, `return@nomeDaFuncao`), não `return` simples (non-local return). O `return` simples dentro de uma lambda `noinline` causa erro de compilação.

### Erros comuns

1. **Usar noinline quando crossinline basta**: se você só precisa impedir non-local return mas não precisa armazenar a lambda, `crossinline` e melhor porque mantém o beneficio de performance do inline.

2. **Marcar todas as lambdas como noinline**: se todas as lambdas são noinline, não há motivo para a função ser inline. O compilador emite um warning nesses casos.

3. **Esquecer que noinline cria objeto**: cada chamada com lambda noinline aloca um objeto Function. Em hot paths, isso pode importar.

4. **Confundir com o comportamento de funções normais**: uma lambda noinline dentro de uma função inline se comporta exatamente como uma lambda em uma função normal -- sem non-local return e com alocacao de objeto.

5. **Nao considerar reified**: se a única razao para a função ser inline e usar `reified`, e todas as lambdas precisam ser noinline, reconsidere o design.

### Termos relacionados

- **inline**: modificador que copia o corpo da função e suas lambdas no local da chamada.
- **crossinline**: impede non-local return mas mantém o inline da lambda.
- **Lambda**: expressao funcional que pode ser passada como argumento.
- **Higher-Order Function**: função que recebe ou retorna lambdas, onde inline/noinline se aplicam.
- **Reified**: tipo generico materializado, disponivel apenas em funções inline.
- **Function object**: objeto criado para representar uma lambda quando ela não e inlineada.

O `noinline` e uma ferramenta de precisao que permite controlar exatamente quais lambdas são inlineadas em uma função inline. Usado corretamente, ele da flexibilidade para armazenar e passar lambdas quando necessário, enquanto as outras lambdas da mesma função continuam aproveitando os beneficios de performance do inline.
