Di adiós a NullPointerException. Trabajando con nulos en Kotlin (KDA 19)
Antonio Leiva

Ya había tardado bastante en dedicarle un artículo a una de las partes más importantes de Kotlin: el tratamiento de nulos.

El propio creador del null reference lo autodenomina como “el error del billón de dólares”, pues es uno de los puntos que más errores genera cuando estás trabajando en este lenguaje.

Si miras a menudo tu gestor de bugs, seguro que el 99% de los errores que ves son NullPointerException.

Gracias a Kotlin, vas a trabajar en un entorno mucho más seguro (incluso con librerías Java), que reducirá al mínimo estos problemas.

¿Te gustaría comenzar hoy a dar el siguiente paso? Te recomiendo que entres en mi training gratuito aquí

training- kotlin-desarrollador-android

Nulos en Kotlin

Los nulos en Kotlin no existen mientras no se diga lo contrario.

Es decir, a ningún objeto, por defecto, se le puede asignar null. Recuerda que en Kotlin todos los tipos son objetos.

Por tanto, esto no compilará:

val x: Int = null

Si quieres que una variable acepte nulos, tienes que marcar el tipo con una ?:

val x: Int? = null

Chequeo en tiempo de compilación

Pero, a partir de ese momento, el compilador te obligará a comprobar el nulo antes de hacer nada con la variable. De esta forma, se asegura de que no se produce un NullPointerException.

Por ejemplo:

val y = x.toDouble()

No compilará, si no compruebas primero si es nulo:

if (x != null) {
    val y = x.toDouble()
}

Expresión de acceso seguro

Existe una expresión mucho más sencilla para representar el ejemplo de antes, que es utilizar una ? delante del . cuando se llama a un método.

Si la variable no es nula, ejecutará la operación. En caso contrario, no hará nada:

val y = x?.toDouble()

En este caso, lo que hará si x es null, es devolver null también. Por lo que y será de tipo Double?.

El operador Elvis

¿Pero qué pasa si no queremos tener una variable nullable como resultado de la operación? El operador Elvis (?:) nos permite devolver un valor en ese caso:

val y = x?.toDouble() ?: 0.0

Este código sería equivalente a:

val y = if (x != null) {
    x.toDouble()
} else {
    0.0
}

Spoiler: como ves, la mayoría de las sentencias en Kotlin son a su vez expresiones. Por ejemplo, puedes asignar el resultado de un if a una variable.

Evitando el chequeo de null

Existe un operador (!!) que evitará la necesidad de chequear null si estás completamente seguro de que una variable nunca será nula.

En mi opinión, hay muy pocos casos en los que este operador tiene sentido. Casi siempre hay una solución mejor.

Pero podrías hacer lo siguiente:

val x: Int? = null
val y = x!!.toDouble()

Esto compilaría y produciría una NullPointerException

Lo dicho: mucho cuidado con este operador.

Compatibilidad con Java

Cuando estamos trabajando con librerías Java, podemos encontrarnos ante diferentes situaciones con respecto al chequeo de nulos.

La librería está correctamente anotada

Si se están utilizando adecuadamente las anotaciones @Nullable y @NotNull, tanto las de Java como las propias de Android, Kotlin será capaz de trabajar sin problemas con ellas para deducir cuándo una variables es nula y cuándo no.

Muchas partes del framework de Android ya están anotadas correctamente, así que esto es una ventaja enorme para trabajar con Kotlin.

La librería no tiene anotaciones

Sin embargo, si la librería no está anotada, los tipos serán marcados con un operador especial (una única !), lo que significa que queda en nuestra mano decidir si un parámetro o valor de retorno acepta nulo o no.

Si tenemos acceso al código fuente, lo mejor es comprobar qué valores acepta el código en cuestión que estemos utilizando.

Un ejemplo en Android que no está anotado es la librería de soporte de RecyclerView. Cuando creas un adapter y autogeneras los métodos, por defecto les añadirá una interrogación a los tipos.

Pero si miras el código fuente, te darás cuenta de que nada puede ser null en los métodos que necesitas sobrescribir. Así que puedes deshacerte de todas las interrogaciones, y evitar chequeos de nulos innecesarios.

Conclusión

Los NullPointerException son un horror para cualquier desarrollador en Java, y seguramente representen la mayor parte de los errores que se producen en tu código.

Reducir su número en Kotlin hasta casi cero es muy sencillo, incluso cuando se trabajar con librerías y frameworks en Java.

Sólo esto te evitará horas y horas de depuraciones innecesarias, además de que hará el código mucho más estable.

Si te gusta lo que has visto, te animo a que te apuntes al training gratuito, donde te contaré todo lo que necesitas para aprender a crear tus Apps Android en Kotlin desde cero.

Quizá también te interese…

Kotlin 1.5.0 : Las 5 novedades que puedes empezar a usar hoy

Kotlin 1.5.0 : Las 5 novedades que puedes empezar a usar hoy

Kotlin 1.5.0 ya está aquí, y como siempre trae una serie de novedades que te van a interesar muchísimo. Cabe destacar que a partir de ahora, de acuerdo las nuevas versiones de Kotlin se lanzarán cada 6 meses, independientemente de las nuevas funcionalidades que...

¿Qué es Kotlin y para qué sirve?

¿Qué es Kotlin y para qué sirve?

Kotlin es un lenguaje de programación de código abierto creado por JetBrains que se ha popularizado gracias a que se puede utilizar para programar aplicaciones Android. Pero si has llegado hasta aquí pensando que Kotlin solo se puede usar en Android, lo que te voy a...

2 formas de recolectar Flows en la UI que SÍ funcionan

2 formas de recolectar Flows en la UI que SÍ funcionan

En la serie de artículos sobre Programación Reactiva con Flow hemos visto muchos conceptos, y hemos aprendido cómo aplicarlos al desarrollo Android. Pero hay algo que no hemos hecho del todo bien. Esto es la recolección de Flows desde la Activity (o el Fragment, en...

11 Comentarios

  1. Alberto Hernández

    Si me apuras quizá sea lo mejor del lenguaje, junto a las lambdas y tratamiento de colecciones. Lo malo es que depende de que las bibliotecas estén anotadas, si el API de Android más o menos lo está genial entonces.

    Una pregunta al hilo del gestor de bugs, si tienes una app Kotlin en producción en la Play Store, se cierra por lo que sea y el usuario envía el reporte de errores… ¿el log que aparece en la consola de desarrollador es “usable”?

    Léase, si te dice dónde se produjo el error en tu código o te va a referenciar clases con nombres raros que no sabes de dónde salen (como cuando le pasas proguard y luego necesitas un mapping). Es más, ¿se puede descompilar una app en Kotlin?

    Responder
    • Antonio Leiva

      Pues sinceramente no lo sé, no tengo ninguna App de Kotlin en la Store, pero lo voy a probar porque la verdad que es una pregunta muy interesante. Cuando tenga la respuesta vuelvo por aquí para contestarte 🙂 .

      En cuanto a la decompilación (y estoy casi seguro de que esto va a responder a la pregunta anterior también), en realidad lo que hace es convertir instrucciones de la máquina virtual a código Java. Las instrucciones que utilizan tanto Kotlin como Java son las mismas (la máquina virtual es lo que es), así que doy por hecho que lo que verás al decompilar será una “versión Java” de las instrucciones de la máquina virtual que Kotlin haya usado. Pero en cuanto tenga un rato lo pruebo también.

      Responder
    • Antonio Leiva

      Ok, ya tengo respuestas. El log que aparece en la consola es el mismo que aparece que ves un error en el logcat, pues es simplemente el stacktrace de la excepción. Ese stacktrace es válido, y apunta a la línea correcta. También es compatible con proguard.

      Con respecto a la decompilación, es exactamente lo que intuía. Lo que hace es convertir las instrucciones del a JVM a código Java, por lo que lo transforma en la interpretación que hace de esas instrucciones. Funcionará en Java, pero el código a veces será un poco enrevesado. No puedes obtener el código Kotlin exacto de vuelta en cualquier caso, hasta que alguien haga un decompilador de Kotlin (si es que eso llega a ocurrir).

      Responder
      • Alberto Hernández

        ¡Muchas gracias! Pues siendo compatible con proguard no hay más preguntas, Señoría. Entiendo que teniendo el mapping puedes saber dónde falló exactamente incluso estando ofuscado, ¡interesante!

        Entre esto, que es funcional y que la biblioteca ocupa nada y menos igual me animo a lanzar el siguiente juego con kotlin + libgdx, es lo más parecido a swift + spritekit que hay en el panorama Android 😀

        Responder
    • Luis Angel

      Elvis se me hace tan parecido al viejo confiable operador condicional, lo uso todos los días en Java para asignar un valor a partir de una condición, incluso se puede encadenar, algo que no me queda claro con elvis

      Otra cosa, cuando leo una o dos veces “librería” en vez de “biblioteca” puedo soportarlo, pero esta vez casi apago mi internet y borro todos los datos de navegación al ver tantas veces el mismo término incorrecto, en eso sí F.

      Responder
      • Antonio Leiva

        Ambas acepciones están aceptadas, y esto es un contenido gratuito. Eres libre de no leerlo.

        https://es.wikipedia.org/wiki/Biblioteca_(inform%C3%A1tica)

        Habitualmente se emplea el término librería para referirse a una biblioteca, por la similitud con el original inglés library. Ambos términos, biblioteca y librería, son correctos según las definiciones (biblioteca,1​ librería2​) de la RAE

        Responder
  2. Alberto Hernández

    ¿Qué tal el curso? ¡Espero que fuera genial! Conseguiste que me pusiera a cacharrear. Al hilo de los NullPointerException me ha hecho gracia que se tomen tanta molestia en erradicarlo y al mismo tiempo ignoren completamente las checked exceptions. Es lo único que no me gusta nada.

    Así que igual no vemos más NPE en la consola de desarrollador pero sí otras excepciones si se nos olvida poner el try/catch correspondiente en algún caso no contemplado. Curioso porque en Swift no había excepciones pero ahora ya sí las tiene y son checked.

    Responder
    • Antonio Leiva

      Fue muy bien, gracias! La gente salió contenta (o eso me dijeron al menos ?)

      La mayoría de los lenguajes modernos no tienen checked exceptions. A mí me parece que ambas opciones tienen sus pros y sus contras, pero si quieres ver por qué en Kotlin decidieron que fuera así, tienes bastante información en su web: https://kotlinlang.org/docs/reference/exceptions.html

      Responder
      • Alberto Hernández

        Lo estuve leyendo, lo que me concome es que ni siquiera sabes qué excepciones podrían lanzarse en cierto punto, cosa que sabe perfectamente el compilador y el IDE y no te lo dice. ¡Tampoco te autocompleta el catch!

        Hace poco en el código de la biblioteca de billing de Android cambiaron el tipo de excepción de un método. Con Kotlin no me habría enterado de ese cambio, incluso podría estar capturando un tipo de excepción que no se correspondía con el que lanzaba. Me habría enterado cuando se le cerrara a un usuario la app…

        Responder

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de Antonio Leiva Gordillo, con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *