En Kotlin, si no desea inicializar una propiedad de clase dentro del constructor o en la parte superior del cuerpo de la clase, tiene básicamente estas dos opciones (de la referencia del lenguaje):
lazy () es una función que toma un lambda y devuelve una instancia de Lazy que puede servir como delegado para implementar una propiedad lazy: la primera llamada a get () ejecuta el lambda pasado a lazy () y recuerda el resultado, llamadas posteriores para obtener () simplemente devuelve el resultado recordado.
Ejemplo
public class Hello { val myLazyString: String by lazy { "Hello" } }
Entonces, la primera llamada y las llamadas secundarias, donde sea que esté, a myLazyString devolverán "Hola"
Normalmente, las propiedades declaradas como de tipo no nulo deben inicializarse en el constructor. Sin embargo, con bastante frecuencia esto no es conveniente. Por ejemplo, las propiedades se pueden inicializar mediante la inyección de dependencia o en el método de configuración de una prueba unitaria. En este caso, no puede proporcionar un inicializador no nulo en el constructor, pero aún así desea evitar verificaciones nulas al hacer referencia a la propiedad dentro del cuerpo de una clase.
Para manejar este caso, puede marcar la propiedad con el modificador lateinit:
public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } }
El modificador solo se puede usar en propiedades var declaradas dentro del cuerpo de una clase (no en el constructor primario), y solo cuando la propiedad no tiene un captador o definidor personalizado. El tipo de la propiedad debe ser no nulo y no debe ser un tipo primitivo.
Entonces, ¿cómo elegir correctamente entre estas dos opciones, ya que ambas pueden resolver el mismo problema?
fuente
lateinit
expone su campo de respaldo con visibilidad del configurador, por lo que las formas en que se accede a la propiedad desde Kotlin y desde Java son diferentes. Y desde el código Java, esta propiedad se puede configurar inclusonull
sin ninguna comprobación en Kotlin. Porlateinit
lo tanto, no es para la inicialización diferida, sino para la inicialización no necesariamente del código de Kotlin.Lazy
+ almacenado explícitamente.isInitialized()
para hacer eso. Supongo que no hay una forma sencilla de verificar dicha propiedadnull
debido a la garantía de que no puede obtenerlanull
. :) Ver esta demostración .by lazy
puede ralentizar el tiempo de construcción o el tiempo de ejecución?lateinit
para eludir el uso denull
un valor no inicializado. Aparte de esonull
, nunca se debe usar, y conlateinit
nulos se puede eliminar. Así es como amo a Kotlin :)Además de
hotkey
su buena respuesta, así es como elijo entre los dos en la práctica:lateinit
es para la inicialización externa: cuando necesita cosas externas para inicializar su valor llamando a un método.por ejemplo llamando a:
Mientras
lazy
es cuando solo usa dependencias internas de su objeto.fuente
Respuesta muy breve y concisa
lateinit: Inicializa propiedades no nulas últimamente
A diferencia de la inicialización diferida, lateinit permite que el compilador reconozca que el valor de la propiedad no nula no se almacena en la etapa del constructor para compilar normalmente.
Inicialización perezosa
by lazy puede ser muy útil al implementar propiedades de solo lectura (val) que realizan la inicialización diferida en Kotlin.
by lazy {...} realiza su inicializador donde la propiedad definida se usa por primera vez, no su declaración.
fuente
lateinit vs perezoso
lateinit
i) Úselo con la variable mutable [var]
ii) Permitido solo con tipos de datos no anulables
iii) Es una promesa compilar que el valor se inicializará en el futuro.
NOTA : Si intenta acceder a la variable lateinit sin inicializarla, arroja UnInitializedPropertyAccessException.
perezoso
i) La inicialización diferida se diseñó para evitar la inicialización innecesaria de objetos.
ii) Su variable no se inicializará a menos que la use.
iii) Se inicializa solo una vez. La próxima vez que lo use, obtendrá el valor de la memoria caché.
iv) Es seguro para subprocesos (se inicializa en el subproceso donde se usa por primera vez. Otros subprocesos usan el mismo valor almacenado en la memoria caché).
v) La variable solo puede ser val .
vi) La variable solo puede ser no anulable .
fuente
Además de todas las excelentes respuestas, hay un concepto llamado carga diferida:
Utilizándolo correctamente, puede reducir el tiempo de carga de su aplicación. Y la forma de implementación de Kotlin es mediante la
lazy()
cual carga el valor necesario a su variable cuando sea necesario.Pero lateinit se usa cuando está seguro de que una variable no será nula o vacía y se inicializará antes de usarla -eg en el
onResume()
método para Android- y, por lo tanto, no desea declararla como un tipo anulable.fuente
onCreateView
,onResume
y otra conlateinit
, pero a veces no se han producido errores (debido a que algunos eventos comenzaron antes). Entonces, tal vezby lazy
pueda dar un resultado apropiado. Lo usolateinit
para variables no nulas que pueden cambiar durante el ciclo de vida.Todo es correcto anteriormente, pero uno de los hechos es una explicación simple PERDIDO ---- Hay casos en los que desea retrasar la creación de una instancia de su objeto hasta su primer uso. Esta técnica se conoce como inicialización diferida o instanciación diferida. El objetivo principal de la inicialización diferida es aumentar el rendimiento y reducir la huella de su memoria. Si crear instancias de una instancia de su tipo conlleva un gran costo computacional y el programa podría terminar sin usarlo, querrá retrasar o incluso evitar el desperdicio de los ciclos de la CPU.
fuente
Si está utilizando Spring container y desea inicializar un campo de bean no anulable,
lateinit
es más adecuado.fuente
@Autowired lateinit var myBean: MyBean
Si usa una variable inalterable, entonces es mejor inicializar con
by lazy { ... }
oval
. En este caso, puede estar seguro de que siempre se inicializará cuando sea necesario y, como máximo, 1 vez.Si desea una variable no nula, que puede cambiar su valor, use
lateinit var
. En el desarrollo de Android más tarde puede inicializarlo en tales eventos comoonCreate
,onResume
. Tenga en cuenta que si llama a la solicitud REST y accede a esta variable, puede generar una excepciónUninitializedPropertyAccessException: lateinit property yourVariable has not been initialized
, ya que la solicitud puede ejecutarse más rápido de lo que esa variable podría inicializar.fuente