by lazy ou lateinit: qual é mais rápido em Kotlin?

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: o dilema eterno do desenvolvedor Kotlin



Se você já escreveu em Kotlin e precisou adiar a inicialização de uma propriedade, certamente já se perguntou: "O que escolher — by lazy ou lateinit?" Esta pergunta é um verdadeiro sucesso no Stack Overflow (milhares de visualizações, dezenas de discussões). E não é à toa: da escolha correta dependem não apenas a legibilidade do código, mas também o desempenho da aplicação.



Neste artigo, não vamos apenas recontar a documentação. Vamos conduzir uma verdadeira investigação: analisar o funcionamento interno de ambos os mecanismos, comparar sua velocidade, consumo de memória e dar recomendações claras. E no final — resumiremos com ações concretas. Vamos nessa!



O que são lateinit e by lazy? Breve introdução



Para começar, vamos refrescar os conceitos básicos. Ambas as abordagens resolvem o mesmo problema: adiar a inicialização de uma propriedade até o momento do seu primeiro uso. Mas fazem isso de maneiras diferentes.



lateinit var — uma promessa ao compilador



A palavra-chave lateinit diz ao compilador: "Eu prometo que inicializarei esta propriedade antes do primeiro acesso, por enquanto apenas reserve espaço para ela". É usada apenas com var e apenas para propriedades mutáveis. Ideal para injeção de dependência (Dagger, Hilt, Koin) ou para propriedades que são inicializadas no onCreate de uma Activity/Fragment.



class MyActivity : AppCompatActivity() {    lateinit var repository: UserRepository

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) repository = UserRepository() // inicialização }

fun loadUser() { // Se repository não for inicializado — ocorrerá UninitializedPropertyAccessException repository.getUser() }}


by lazy — delegado preguiçoso



O delegado lazy é um mecanismo mais flexível. Ele cria um objeto wrapper que, no primeiro acesso, executa uma lambda e armazena o resultado. Todos os acessos subsequentes apenas retornam o valor armazenado. Por padrão, é thread-safe (sincronizado), mas é possível configurar o modo.



class MyViewModel : ViewModel() {    val heavyData: ExpensiveData by lazy {        // Este bloco será executado apenas uma vez, no primeiro acesso        ExpensiveData()    }}


Ambas as abordagens resolvem o problema da "inicialização preguiçosa", mas fazem isso com diferentes compromissos. Vamos analisar esses compromissos em detalhes.



Desempenho: qual é mais rápido?



Aqui chegamos ao mais interessante — aos números. Desempenho não é apenas a velocidade de acesso à propriedade, mas também a sobrecarga de inicialização, memória e segurança de thread.



Velocidade do primeiro acesso



lateinit — o recordista absoluto. No primeiro acesso, o compilador apenas verifica se o campo não é nulo (se for nullable — lança uma exceção). Sem lambdas, sem sincronizações. É praticamente gratuito.



by lazy — mais lento. No primeiro acesso, um bloco sincronizado é chamado (se o modo padrão for LazyThreadSafetyMode.SYNCHRONIZED), a lambda é executada e o resultado é armazenado em cache. Isso leva microssegundos, mas em loops de alta carga ou em código crítico pode ser perceptível.



Velocidade de acessos repetidos



Após a inicialização, ambas as abordagens funcionam igualmente rápido. lateinit apenas lê o campo (como um var comum). by lazy após a primeira inicialização também lê o valor em cache. A diferença de velocidade nesta etapa é praticamente zero.



Consumo de memória



Aqui, lateinit vence de lavada. Ele não c

Blogs

Book Recommendations