En este tutorial se habla de Kotlin, un lenguaje que funciona sobre la JVM, como alternativa Java
Índice de contenidos
- 0. ¿Qué es Kotlin?
- 1. Kotlin y Android
- 2. Añadir Kotlin a un proyecto Android
- 3. Porqué usar Kotlin en Android
- 10. Conclusiones
¿Qué es Kotlin?
Kotlin es un lenguaje que funciona sobre la JVM, es una alternativa moderna a Java priorizando la compatibilidad con Java. Intenta solucionar los problemas más comunes de Java cómo pueden ser las Null Pointer Exception
o la verbosidad.
Algunas de las características más destacadas de Kotlin son:
- Fuerte inferencia de tipos, sobre todo trabajando con genéricos.
- Protección frente a
null
, los tipos por defecto no pueden sernull
, en caso de que un tipo venga de un API de Java, Kotlin te obliga a tener en cuenta esenull
. - Características de programación funcional, cómo higher order functions, Pattern Matching y otras funcionalidades provenientes de lenguajes funcionales.
Kotlin y Android
Google eligió Java cómo lenguaje para Android, a pesar de que Java ha seguido evolucionando desde ese momento, en Android se sigue utilizando Java 6 (aunque con algunas características de Java 7), a estas versiones se les empieza a notar la edad, teniendo en cuenta todos los avances que han ido habiendo en el diseño de lenguajes, plasmado en algunos cómo Scala o Swift.
Kotlin soluciona muchos de los problemas que tiene Java sin añadir demasiada complejidad, es un lenguaje pequeño que puede usar todas las librerías que ofrece la JVM sin problemas, por lo que no se convierte en una apuesta arriesgada.
Todo ello sin perder la genial integración con Android Studio que ya conocemos con Java.
Además, la naturaleza de las aplicaciones Android, las cuales están bastante ligadas a la capa de presentación, las hace perfectas para un lenguaje cómo Kotlin, el cual es mucho más dinámico que Java.
Algo a tener en cuenta también es la posibilidad de mezclar clases Java y Kotlin en el mismo proyecto, de manera que migrar proyectos ya existentes a Kotlin no debería ser una tarea titánica sino algo progresivo.
Añadir Kotlin a un proyecto Android
Voy a dar por hecho de que el proyecto ya está usando Gradle, si no lo hace deberías migrarlo antes de nada
Para añadir Kotlin a nuestro proyecto, es tan fácil cómo añadir el plugin de Kotlin para Gradle, el cual se encargará de compilar el código de Kotlin de manera que pueda ser ejecutado en Android sin problema y añadir la dependencia de la librería standard de Kotlin.
En el build.gradle de nuestro proyecto "padre":
buildscript { ext.support_version = '22.2.1' ext.kotlin_version = '0.12.1218' ext.anko_version = '0.6.3-15s' repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { repositories { jcenter() } }
Y el build.gradle del proyecto de aplicación:
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { ... } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.anko:anko:$anko_version" ... } buildscript { repositories { jcenter() } dependencies { classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" } }
Hemos añadido también la librería Anko, esta librería escrita en Kotlin, nos ofrece una serie de funciones de ayuda para agilizar el desarrollo en Android usando Kotlin, estas son totalmente opcionales pero no serán de gran ayuda.
El siguiente paso sería crear un fichero .kt
para comprobar que todo se ha instalado correctamente, para ello en el mismo paquete donde tengamos nuestras clases creamos un fichero de utilidades que nos ayudará con el manejo de trazas.
import android.util.Log public val LOG_ENABLED: Boolean = true; public val TAG: String = "HNNotify" public fun log(text: String) { if (LOG_ENABLED) { Log.d(TAG, text) } }
Una vez creada, podemos probar en cualquier actividad si se está ejecutando correctamente, para ello debemos importar el paquete.
import static com.danieldisu.utils.UtilsPackage.*; public fun logIfItWorks() { log("Hello World"); }
Por convención Kotlin crea un paquete usando el nombre del paquete y la palabra "Package"
Porqué usar Kotlin en Android
A continuación voy a repasar algunas de las cosas que más me han gustado de usar Kotlin en Android, que suelen ir de la mano con los mayores puntos de verbosidad de Java.
Lambdas
Gracias a Java 8 las lambdas se han hecho conocidas en el mundo Java, aunque ya las usábamos de una manera u otra en Java desde bastante antes, por ejemplo, al añadir un OnClickListener
a un botón en Android, extendíamos la clase abstracta y sobrescribíamos el único método de esta clase, el cual se llamará en el momento en el que el usuario pulse el botón. En otros muchos lenguajes cómo Javascript, esto se soluciona pasando una función por parámetro e invocando está función en el momento adecuado, Kotlin nos permite hacer esto mismo.
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { log("User clicked!"); } });
En kotlin sería:
button.onClick { onUpdateButtonClick(it) }
o sin abreviar:
updateButton.onClick { view -> onUpdateButtonClick(view)}
El método onClick
lo añade la librería Anko, al final solo es una manera corta de llamar al método setOnClickListener
, en cuanto a la invocación, al tener un solo parámetro podemos usarlo con la keyword it
.
Esto es posible gracias al siguiente punto:
Extender clases del sistema o librerías.
Kotlin nos permite añadir métodos/funciones a clases y librerías externas, cómo pueden ser las clases de Android, lo que nos permite hacer métodos de utilidad que podrán ser invocados con notación infija, lo cual nos dará la sensación de que los métodos pertenecen a la clase, además de permitir al IDE ofrecernos estos métodos cómo un método más al escribir el punto tras una variable.
public fun android.view.View.onClick(l: (v: android.view.View) -> Unit): Unit = setOnClickListener(l)
Esta es la función que nos extiende la clase View
de Android permitiéndonos invocar al método onClick para añadir un listener.
Estas extensiones tienen limitaciones, ya que se resuelven de manera externa, no pueden acceder a ningún atributo privado de la clase, pero sí a otros métodos no estáticos.
Null safety
Kotlin es un lenguaje que ha sido creado para solucionar los problemas más comunes en Java, uno de ellos y quizás el que más problemas crea de manera indirecta es la existencia de nulos. Para ello Kotlin no permite inicializar ninguna variable a null a no ser que declaremos esa variable cómo nullable, es decir declarando explícitamente en el sistema de tipos que esa variable puede contener null
. Además, obliga que al usar cualquier variable declarada cómo nullable tengamos en cuenta la posibilidad de que esta puede ser null
.
Vamos a ver cómo es esto en la práctica:
public var nullableString: String? = null public var nonNullableString: String = null public var nonNullableString: String
En este caso solo la primera línea será válida, la segunda y tercera producirán un error de compilación.
fun functionThatUsesString(string: String): Unit { log(string) } fun main(){ functionThatUsesString(nullableString) }
Esto producirá un error de compilación, ya que functionThatUsesString
necesita un String
y nullableString
es de tipo String?
, para evitar esto podemos hacerlo de varias maneras:
var nullableString: String? = null; if (nullableString != null) functionThatUsesString(nullableString) else doSomethingElse()
Hacemos exactamente lo mismo que haríamos en Java, pero esta vez obligados por el compilador, lo cual nos ofrece la garantía de que se está teniendo en cuenta.
var nullableString: String? = null; functionThatUsesString(nullableString ?: "otherString")
Usando el operador ?:
que nos permite proponer una alternativa en caso de que este sea null
.
var nullableString: String? = null; functionThatUsesString(nullableString!!)
Si estamos completamente seguros de que no va a ser null
podemos usar el operador !!
que nos ofrece Kotlin, en caso de que si fuese null
lanzará un Null Pointer Exception
, por ello este método no es el más aconsejado.
Data Classes
Muchas veces creamos clases que no son más que contenedores de información, en Java una sencilla clase con 3 atributos nos obligaría a hacer un total de 8 métodos (getters , setters, equals y hashcode), podemos definirlas en una sola línea usando la anotación data
sobre una clase:
public class Person { private String name; private String surname; private int age; public Person(String name, String surname, int age) { this.name = name; this.surname = surname; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; if (age != person.age) return false; if (name != null ? !name.equals(person.name) : person.name != null) return false; return !(surname != null ? !surname.equals(person.surname) : person.surname != null); } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (surname != null ? surname.hashCode() : 0); result = 31 * result + age; return result; } }
Tanto los getter/setter cómo equals y hashCode han sido auto generados por AndroidStudio
VS la versión de Kotlin:
data class User(val name: String, val surname: String, val age: Int)
When Expression
When
es un paso intermedio entre el clásico Switch
y match
(Pattern Matching) en Scala y otros lenguajes funcionales. Básicamente lo que nos permite es hacer algo cuando una de las condiciones se cumpla:
Se puede usar directamente con valores:
when (x) { 1 -> print("x == 1") 2 -> print("x == 2") else -> { // Note the block print("x is neither 1 nor 2") } }
Con valores que se obtienen tras invocar un método:
when { x.isOdd() -> print("x is odd") x.isEven() -> print("x is even") else -> print("x is funny") }
O con tipos:
when (x) { is String -> println("isString!") is StringBuffer -> println("isStringBuffer!") else -> println("isOtherThing") }
Interoperabilidad con Java
Uno de los principales aspectos de diseño de Kotlin es mantener la interoperabilidad al máximo con Java, esto nos permite usar la gran mayoría de las librerías ya existentes sin ningún tipo de problema.
En este sencillo ejemplo estamos usando Retrofit, Gson, RxJava sin ningún tipo de problema:
public interface HNService { GET("/item/{itemId}.json") fun getItem(Path("itemId") itemId: String): Observable<HNItem> } object HNClient { private var client: HNService? = null fun get(): HNService { return this.client ?: createNewClient(); } private fun createNewClient(): HNService { val restAdapter = RestAdapter.Builder() .setEndpoint("https://hacker-news.firebaseio.com/v0") .build(); val hnClient = restAdapter.create(javaClass<HNService>()) this.client = hnClient return hnClient; } } data class HNItem(val by: String, val descendants: Int, val id: Int, val kids: Array<Int>, val score: Int, val time: Long, val title: String, val type: String, val url: String) { }
Conclusiones
Hay gente que opinará que esto es solo syntax sugar y que quizás no sea necesario, pero cómo dijo Andrey Breslav (dev lead de Kotlin) en una charla, "todos los lenguajes son syntax sugar sobre código máquina" , por ello creo que debemos dejarnos ayudar por este tipo de avances, que ayudan no solo a la hora de desarrollar si no a la hora de leer y mantener el código.
Kotlin además es un paso intermedio entre Java y Scala por lo que lo hace un lenguaje más atractivo para aquellos que no necesiten (o quieran) un lenguaje tan potente como Scala, además de ser bastante más pragmático y menos académico.
Hola, una pregunta, para un ser humano que no sabe nada de nada. Por donde debo empezar?
Hola, puedes empezar por entender POO https://www.edx.org/es/course/programacion-orientada-objetos-mexicox-upevipn02x, después iniciarse en java con este curso https://codigofacilito.com/cursos/JAVA
Very nice information