No Kotlin, se você não deseja inicializar uma propriedade de classe dentro do construtor ou na parte superior do corpo da classe, você tem basicamente essas duas opções (da referência de idioma):
lazy () é uma função que pega um lambda e retorna uma instância do Lazy que pode servir como um delegado para implementar uma propriedade preguiçosa: a primeira chamada a get () executa o lambda passado a lazy () e lembra o resultado, chamadas subseqüentes para obter (), simplesmente retorne o resultado lembrado.
Exemplo
public class Hello { val myLazyString: String by lazy { "Hello" } }
Portanto, a primeira chamada e as chamadas subquenciais, onde quer que estejam, para myLazyString retornarão "Hello"
Normalmente, as propriedades declaradas como tendo um tipo não nulo devem ser inicializadas no construtor. No entanto, com bastante frequência isso não é conveniente. Por exemplo, as propriedades podem ser inicializadas por injeção de dependência ou no método de configuração de um teste de unidade. Nesse caso, você não pode fornecer um inicializador não nulo no construtor, mas ainda deseja evitar verificações nulas ao fazer referência à propriedade dentro do corpo de uma classe.
Para lidar com esse caso, você pode marcar a propriedade com o modificador lateinit:
public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } }
O modificador só pode ser usado em propriedades var declaradas dentro do corpo de uma classe (não no construtor primário) e somente quando a propriedade não possui um getter ou setter personalizado. O tipo da propriedade deve ser não nulo e não deve ser um tipo primitivo.
Então, como escolher corretamente entre essas duas opções, pois ambas podem resolver o mesmo problema?
fonte
lateinit
expõe seu campo de suporte com visibilidade do setter, de modo que as maneiras pelas quais a propriedade é acessada no Kotlin e no Java são diferentes. E a partir do código Java, essa propriedade pode ser configurada mesmonull
sem nenhuma verificação no Kotlin. Portanto,lateinit
não é para a inicialização lenta, mas para a inicialização não necessariamente do código Kotlin.Lazy
+ armazenado.isInitialized()
para fazer isso. Acho que não há uma maneira direta de verificar essa propriedade pornull
causa da garantia de que você não pode obternull
dela. :) Veja esta demonstração .by lazy
podem retardar o tempo de compilação ou o tempo de execução?lateinit
para contornar o uso denull
valores não inicializados. Fora issonull
, nunca deve ser usado e comlateinit
valores nulos podem ser eliminados. É assim que eu amo Kotlin :)Além
hotkey
da boa resposta, aqui está como eu escolho entre os dois na prática:lateinit
é para inicialização externa: quando você precisa de itens externos para inicializar seu valor chamando um métodopor exemplo, chamando:
Enquanto
lazy
é quando ele usa apenas dependências internas ao seu objeto.fonte
Resposta muito curta e concisa
lateinit: inicializa propriedades não nulas recentemente
Diferentemente da inicialização lenta, o lateinit permite que o compilador reconheça que o valor da propriedade não nula não é armazenado no estágio do construtor para compilar normalmente.
Inicialização lenta
por lazy pode ser muito útil ao implementar propriedades somente leitura (val) que executam a inicialização lenta no Kotlin.
by lazy {...} executa seu inicializador onde a propriedade definida é usada pela primeira vez, não sua declaração.
fonte
lateinit vs lazy
lateinit
i) Use-o com a variável mutável [var]
ii) Permitido apenas com tipos de dados não anuláveis
iii) É uma promessa para o compilador que o valor será inicializado no futuro.
NOTA : Se você tentar acessar a variável lateinit sem inicializá-la, ela lançará UnInitializedPropertyAccessException.
preguiçoso
i) A inicialização lenta foi projetada para impedir a inicialização desnecessária de objetos.
ii) Sua variável não será inicializada, a menos que você a utilize.
iii) É inicializado apenas uma vez. Da próxima vez que você usá-lo, você obtém o valor da memória cache.
iv) É seguro para threads (é inicializado no thread em que é usado pela primeira vez. Outros threads usam o mesmo valor armazenado no cache).
v) A variável só pode ser val .
vi) A variável só pode ser nula .
fonte
Além de todas as ótimas respostas, existe um conceito chamado carregamento lento:
Usando-o corretamente, você pode reduzir o tempo de carregamento do seu aplicativo. E Kotlin maneira de sua implementação é por
lazy()
carregar o valor necessário para sua variável sempre que necessário.Mas o lateinit é usado quando você tem certeza de que uma variável não será nula ou vazia e será inicializada antes de usá-la - por exemplo, no
onResume()
método para android - e, portanto, não deseja declará-la como um tipo que pode ser nulo.fonte
onCreateView
,onResume
e outros comlateinit
, mas às vezes ocorreram erros (porque alguns eventos começaram anteriormente). Então, talvezby lazy
possa dar um resultado apropriado. Eu usolateinit
para variáveis não nulas que podem mudar durante o ciclo de vida.Tudo está correto acima, mas um dos fatos é a explicação simples LAZY ---- Existem casos em que você deseja atrasar a criação de uma instância do seu objeto até o seu primeiro uso. Essa técnica é conhecida como inicialização lenta ou instanciação lenta. O principal objetivo da inicialização lenta é aumentar o desempenho e reduzir o consumo de memória. Se a instanciação de uma instância do seu tipo acarretar um grande custo computacional e o programa acabar realmente não a utilizando, convém adiar ou mesmo evitar o desperdício de ciclos da CPU.
fonte
Se você estiver usando o contêiner Spring e desejar inicializar o campo do bean não anulável,
lateinit
é mais adequado.fonte
@Autowired lateinit var myBean: MyBean
Se você usar uma variável imutável, é melhor inicializar com
by lazy { ... }
ouval
. Nesse caso, você pode ter certeza de que sempre será inicializado quando necessário e no máximo 1 vez.Se você deseja uma variável não nula, isso pode mudar seu valor, use
lateinit var
. No desenvolvimento do Android mais tarde você pode inicializá-lo em tais eventos comoonCreate
,onResume
. Esteja ciente de que, se você chamar a solicitação REST e acessar essa variável, poderá levar a uma exceçãoUninitializedPropertyAccessException: lateinit property yourVariable has not been initialized
, porque a solicitação pode ser executada mais rapidamente do que a variável poderia inicializar.fonte