Propiedades lateinit En Kotlin

En este tutorial hablaremos sobre las propiedades lateinit en Kotlin y cómo pueden proveerte un mecanismo para inicialización tardía

El Modificador lateinit

El modificador lateinit te permite inicializar una propiedad no anulable por fuera del constructor.

Este mecanismo te ayuda cuando deseas asignar el valor de una propiedad después y no deseas usar comprobaciones de nulos (expresiones if, operador de acceso seguro o aserciones) una vez inicializada.

lateinit var propiedad:String

Restricciones De Propiedades lateinit

Ten en cuenta las siguientes restricciones a la hora de definir una propiedad lateinit:

  • Deben ser propiedades mutables var (es evidente, ya que necesitas cambiar el valor fuera del constructor)
  • Debe declararse en el cuerpo de la clase, no el constructor primario
  • No deben tener accesores (get y set) personalizados
  • No pueden declararse con tipos primitivos
  • No pueden ser anulables

Ejemplo De Propiedades lateinit En Kotlin

Supongamos que hemos creado un pequeño framework para videojuegos compuesto de las clases Game y VideoController.

Game representa a la entidad maestra que controla las reglas del mundo y la creación de las abstraciones como VideoController.

Y VideoController es el controlador asociado a la creación de escenas y renderizado.

Solución Con Propiedad Anulable

Proveeremos a Game de dos métodos, init() para inicializar el componente de video y createScene() para generar la escena preliminar.

class VideoController(var screenWitdh: Int, var screenHeight: Int)
class Game {
    private var videoController: VideoController? = null

    fun init(witdh:Int, height:Int) {
        videoController = VideoController(witdh, height)
    }

    fun createScene() {
        print("Resolución de ${videoController?.screenWitdh}x" +
                "${videoController?.screenHeight}")
    }

}

Como no podemos dejar a videoController sin valor hasta init(), entonces lo declaramos como anulable para asignarle null.

En createScene() usaremos el operador de acceso seguro .? para acceder a screenWitdh y screenHeight.

Como puedes notar, si en el futuro tuviésemos más usos del controlador de video dentro de Game, tendríamos grandes cantidades de comprobaciones de nulos.

Resolvamoslo con el modificador lateinit.

Solución Con Propiedad lateinit

Usa el modificador lateinit en la declaración de videoController.

private lateinit var videoController: VideoController

Inmediatemente IntelliJ IDEA te sugerirá que ya no es necesario el uso del operador ?.:

Unnecessary safe call Kotlin

Así que retiralos:

fun createScene() {
    print("Resolución de ${videoController.screenWitdh}x" +
            "${videoController.screenHeight}")
}

Ahora prueba su funcionamiento creando una instancia de Game, inicializa los componentes y luego crea la escena:

fun main() {
    val game = Game()
    game.init(800,600)
    game.createScene()
}

En la salida tendrás:

Resolución de 800x600

Comprobar Inicialización Con isInitialized

Si intentas comentar la línea game.init(800,600) de la ejecución anterior, obtendrás una excepción del tipo UninitializedPropertyAccessException:

Exception in thread "main" kotlin.UninitializedPropertyAccessException:
lateinit property videoController has not been initialized

Y es algo que se esperaba, el valor no tiene un valor de inicialización, ya que no se respetó la secuencia de tu framework.

Para determinar si la propiedad fue o no inicializada, llama a isInitialized en la referencia de la propiedad.

Por ejemplo, en createScene() puedes verificar la propiedad isInitialized antes de acceder al controlador de video. Si no ha sido inicializada crea un controlador por defecto.

class Game {
   
 //...
    fun createScene() {
        if (!this::videoController.isInitialized) {
            videoController = VideoController(300, 300)
        }

        print(
            "Resolución de ${videoController.screenWitdh}x" +
                    "${videoController.screenHeight}"
        )
    }

}

Al ejecutar el programa sin llamar a init() tendrás:

Resolución de 300x300

Únete Al Discord De Develou

Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!