Alerta Coder 3 – ¿Lateinit o nulable?
Muchas veces tenemos la duda (o a lo mejor no) de si deberíamos declarar una propiedad como lateinit
o como nulable (aquí tienes Kotlin.org, por si no sabes lo que es lateinit
: https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties-and-variables
La solución se encuentra en preguntarnos lo siguiente: «¿debe mi aplicación seguir adelante si esto es nulo?».
- Cuando declaramos algo como nulable estamos indicando que el valor nulo es uno de los posibles estados de esa propiedad y que nuestra aplicación es capaz de dar respuesta a esta situación.
Por ejemplo, tenemos una aplicación que crea personas mediante un formulario. Si la aplicación nos permite pulsar el botón Finalizar antes de que el formulario esté completo porque va a mostrar un mensaje de error indicando qué campos faltan por especificar, todos esos campos son nulables, ya que si los campos son nulos, la aplicación tiene prevista una respuesta correcta.
- Sin embargo, cuando declaramos una propiedad como
lateinit
estamos diciéndole al compilador que, este campo no puede ser nulo y que, para cuando la aplicación tenga la necesidad de utilizar esa propiedad, sabemos a ciencia cierta que esta va a estar inicializada.
Por ejemplo, cuando inyectamos vistas con ButterKnife en un fragment, en el métodoonCreateView()
obtenemos unUnbinder
que usamos para desvincular las vistas en elonDestroyView()
. Esteunbinder
podemos declararlo comolateinit
, ya que sabemos a ciencia cierta que, para cuando lo llamemos enonDestroyView()
, va a estar inicializado; y es inadmisible que elunbinder
sea nulo. Si es nulo en ese punto, has programado mal.
Otra pista para saber si deberíamos hacer algo nulable en lugar de lateinit
es cuando nos preguntamos «¿estará inicializada esta propiedad para
cuando llegue a esta línea?». Si te lo estás preguntando es porque sabes
que, para la aplicación, es un estado posible el llegar ahí y que esa
propiedad no tenga valor, por lo tanto, es nulable.
Curiosidades
Primera
Todo lateinit
tiene una propiedad que indica si está incializada o no: isInitialized
, y solo se puede acceder a esta de la siguiente manera:
1 2 3 |
lateinit var persona: Persona if (::persona.isInitialized) {} |
Pero esto SOLAMENTE debería ser utilizado para depurar, nunca en producción, ya que, si tienes que comprobar esto, es porque estás, con total seguridad, lidiando con una propiedad que debería ser nulable.
Puedes ver algo más de documentación sobre esto aquí y aquí.
Segunda
No se pueden declarar como lateinit
aquellos objetos que en Java se traducen por tipos primitivos:
1 2 |
lateinit var unValor: Boolean lateinit var unNumero: Int |
Ninguno de estos funciona y el compilador te avisará de ello.
Tercera
Puedes simular un lateinit
para tipos primitivos utilizando el delegate notNull
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import kotlin.properties.Delegates class MiClase { private var valor: Int by Delegates.notNull() fun algunMetodo() { valor = 4 } fun algunOtroMetodo() { print(valor) // Igual que lateinit, fallará si no se ha llamado a "algunMetodo" antes. } } |