Kotlin, el sucesor de Java o algo mejor

Autor: | Última modificación: 19 de febrero de 2024 | Tiempo de Lectura: 6 minutos
Temas en este post:
Kotlin sin lugar a dudas ha sido el lenguaje del momento en lo que va del 2017. Su anuncio como lenguaje oficial para Android ha sido la guinda del pastel, colocándolo como un lenguaje a tener en tu arsenal, especialmente si te interesa el desarrollo nativo en la plataforma Android o, si como yo, trabajas en aplicaciones Java para backend. Y si todavía no te convence, aquí tienes 7 razones por las que deberías aprender Kotlin. A pesar de que muchos catalogan a Kotlin como el sucesor de Java, este lenguaje no fue diseñado solamente con el propósito de reemplazarlo. Desde mi perspectiva, Kotlin viene con una meta más ambiciosa: ser un lenguaje de programación no dependiente de la plataforma. Por tanto sería un lenguaje universal único que permitirá crear aplicaciones de front-end, backend, móvil y hasta para plataformas no dependientes de la JVM (más sobre esto después). Por estas razones este artículo será dividido en dos partes. Primero compararemos algunas de las ventajas de Kotlin sobre Java y explicaré cómo este lenguaje puede salvarte unas buenas líneas de código y hacer tu experiencia más agradable. En la segunda parte hablaré un poco sobre las funcionalidades que han sido añadidas en Kotlin que, aunque no estén presente en Java, son muy interesantes.

Making Java JVM programming great again!

Data classes

Muchos comentan sobre lo bueno que Kotlin no requiere “;” al final de cada statement, a otros grupos les fascina que Kotlin es null save por defecto; pero para mí, la primera funcionalidad que me llamó la atención son las data classes, especialmente viniendo de Java. Para las personas como yo que han trabajado con Java MVC web frameworks (ejemplo: Spring-Boot, Spark web framework, Play, etc.), la tarea repetitiva de crear un java file por cada modelo es muy tediosa, además en cada modelo debemos declarar su fields y los famosos getters and setters (no es obligado, pero es una buena práctica). Esto se vuelve una tarea repetitiva y aburrida en mi opinión, ¡pero ya no más! Si decides cambiarte a Kotlin 🙂 Kotlin introduce el concepto de data classes. Básicamente, puedes declarar clases que sólo se usan para contener información, y éstas siguen el mismo propósito que los Java Pojo (Plain Old Java Object), y además viene out of the box con la implementación de los métodos toString(), hashCode() / equlas() y copy().

Ejemplo en Java

public class Pet {
    private Integer age;
    private String name;

    public Pet(String name, Integer age) {
        this.age = age;
        this.name = name;
    }

    public Pet(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        if (this.age == null)
            return 0;
        else
            return age;
    }

    @Override
    public String toString() {
        return "Pet(name= " + this.name + ", age=" + this.age + ")";
    }
    
        public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        if (!super.equals(object)) return false;

        Pet pet = (Pet) object;

        if (age != null ? !age.equals(pet.age) : pet.age != null) return false;
        if (name != null ? !name.equals(pet.name) : pet.name != null) return false;

        return true;
    }

    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + (age != null ? age.hashCode() : 0);
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }
}

Ejemplo en Kotlin

data class Pet(val name: String, val age: Int = 0)

Null safety by default

Kotlin ha sido diseñado desde el principio para hacer el valor null explícito, esto quiere decir, que para lograr un null value en Kotlin, nosotros como programadores tenemos que declarar explícitamente una variable como nullable. Esta tendencia en lo particular me gusta bastante, ya que todo programador Java ha tenido que sufrir el malévolo NPE (formalmente conocido como Null Pointer Exception) al menos una vez. Java 8, tratando mejorar este problema, añadió la clase Optional<T>, la cual actúa como una class wrapper para añadir safety a nuestras instancias, pero en mi opinión, el código se torna verboso y aburrido de escribir. Todos sabemos que permitir null en nuestro código es un riesgo, por lo que Kotlin ha introducido Null safety en el tiempo de compilación.

Ejemplo en Kotlin

var name: String = "Alberto" // permitido

name = null // No permitido, error al compilar

var lastName: String = null // no permitido, error al compilar

var secondName: String? = "Andres" // permitido

secondName = null // permitido, tenemeos que usar el operador “?” ya que explicitamente sabemos que la variable <secondName> puede ser null

Smart Cast

Una de las funciones que me encanta de Kotlin es el smart casting. En Java, cuando obtienes un objeto que viene de una super class pero necesitas usarlo como una subclase, tienes que realizar casting en una nueva variable, esto hace que, a mi parecer, el código se vuelva muy denso. Pero Kotlin simplifica este tedioso proceso al agregar smart casting. Introduce el operador “is”, el cual actúa como un operador booleano que, si acierta, realiza un cast a la variable usada en su argument permitiéndote usarla directamente como su subclase sin crear una nueva instancia. Pero como siempre menos palabras y más código 🙂

Ejemplo en Java

public int printLenghtOfString(Object stringObject) {
    if (stringObject instanceof String) {
        String nowIsString = (String) stringObject;
        return nowIsString.length();
    } else {
        return  0;
    }
}

Ejemplo en Kotlin

fun printLengthOfString(stringObject: Any) = if (stringObject is String) stringObject.length else 0

Kotlin extras

En esta segunda parte voy a hablar brevemente sobre 2 funcionalidades muy interesantes, como son las extensions functions y la nueva adición en Kotlin 1.1: coroutines.

Extension functions

Algo que siempre me ha molestado de Java es que uno tiene que escribir mucho código para hacer cosas simples. Pongamos el caso en el cual queremos crear un método específico para una clase existente. Para nuestro ejemplo vamos a  crear un método que retorne el piso del average de una lista de Int. En Java tienes 2 opciones.
  1. Puedes crear una clase que extienda de la interfaz List y añadimos nuestro método. Pero ahora en nuestra aplicación tendremos que referenciar esta clase en vez de la interface List cada vez que queramos usar nuestro nuevo método, además tendrás que recordarte que, cada vez que quieras usar el método floor, debes utilizar tu nueva clase.
  2. Puedes crear una static helper class, en la cual puedes definir tu método, pero tendrás que importar esta helper class en cada ocasión que quieras usarlo.
Mucho código para tan simple tarea. Por esto Kotlin ha añadido extensions functions. Esta funcionalidad te permite extender una clase existente con nueva funcionalidad sin tener que crear nuevas clases. ¡Simplemente maravilloso! 🙂
// Esto es la declaracion de una extension function de la clase List<Int>
// La funcionalidad es retornar el "piso" del average de una una List de Ints
// Mas sobre la funcion "piso": http://www.allmathwords.org/es/f/floorfunction.html
fun List<Int>.floor(): Int = this.reduce {i1, i2 -> i1 + i2} / this.size

// Prueba de nuestro codigo
fun main(args: Array<String>) {
    val list = mutableListOf<Int>(1, 2, 3, 4, 5, 6, 7, 8, 9)
    val floor = list.floor() // ahora nuestra lista de Int incluye el metodo floor() (sin tener que repetir nuestro coddigo de implementacion)
    println(floor) // --> Display: 5.0
}

Coroutines

Concurrencia es una necesidad para las aplicaciones de hoy en día, especialmente si trabajas en el backend. Como sabemos la mayoría de programadores Java, las threads consumen muchos recursos del sistema y pueden transformar nuestro código en programas complicados de entender y difícil de sincronizar. Ha habido muchas ideas para tratar de mejorar la experiencia de escribir código concurrente en Java, como son por ejemplo las famosas callbacks y recientemente una de mis librerías favoritas, RxJava, que se basa en las especificaciones de Reactive Streams, pero todas estas opciones siguen añadiendo complejidad a la hora de leer y entender el código. Los diseñadores de Kotlin han decidido usar un enfoque diferente a las threads convencionales y han decidido implementar las muy interesantes coroutines. Basándonos en la definición oficial de los creadores de este lenguaje, una coroutine es una instancia de computación suspendible… sí, yo tampoco lo entendí la primera vez que lo leí ;). En cristiano, una coroutine te permite ejecutar un bloque de código concurrentemente. Este bloque de código puede ser iniciado por una Thread A, suspendido y retomado por otra Thread B, conocido formalmente como work stealing, esto y otras optimizaciones permiten a las coroutines consumir pocos recursos en términos de CPU. Además, una característica importante es que el código, al leerlo es muy parecido al código convencional imperativo, haciendo que sea fácil de entender. Las coroutines son un poco más avanzadas que otros elementos básicos de Kotlin, pero he decidido hablar un poco de ellas ya que han sido la característica más importante añadida en Kotlin 1.1. Para una introducción a este tema adjunto este video de JetBrainsTv, donde Andrey Breslav presenta algunas de las características de Kotlin 1.1, entre ellas coroutines 😉
YouTube video

Bonus: Native Kotlin

Como expliqué al principio de este artículo, Kotlin viene para quedarse, y no sólo con el area mobile, backend (JVM) y frontend. La meta global del equipo Kotlin es crear un lenguaje nativo que pueda ser compilado dependiendo de la plataforma requerida (target). Un claro ejemplo son los sistemas embebidos. En la actualidad el software de los dispositivos IoT se realiza con lenguajes de menos nivel que Java, como por ejemplo nuestro viejo amigo C, pero el equipo de Kotlin quiere cambiar esta tendencia. Viendo los avances en hardware, el equipo Kotlin cree que un lenguaje de más alto nivel que C o C++ como Kotlin podría hacer el desarrollo de sistemas embebidos más fluidos y, además, colocar a Kotlin como un lenguaje universal. El proyecto Kotlin Native todavía se encuentra en sus primeras fases, por lo cual no esperes verlo en producción a corto plazo. Pero la verdad es que cuando este proyecto vea la luz del día en la industria podría llegar a ser un real game changer. Para más información sobre Native Kotlin te dejo su repo de GitHub.

Bonus 2: Recursos

Libros y sitios online de referencia

Backend frameworks que soportan kotlin oficialmente

Si tienes algo que deseas compartir o quieres formar parte de KeepCoding, escríbenos a [email protected].