Está en la página 1de 13

Ventajas de usar Kotlin

Ventajas de usar Kotlin 1


¿Qué aprenderás? 2
Introducción 2
Properties y cómo acceder a ellas 3
Inicialización tardía de propiedades y variables 4
Null Safety 6
¿Qué es un error de null? 6
Llamadas seguras (safe calls) 7
Operador !! 9
Operador Elvis 10
When 11

¡Comencemos!

_ 1

www.desafiolatam.com
¿Qué aprenderás?

● Properties y cómo acceder a ellas.


● Inicializar tardíamente properties.
● Usar Null Safety.
● Manejar los operadores del null safety.
● Utilizar sentencia When.

Introducción

Kotlin al ser un lenguaje moderno, tiene ciertas ventajas que vienen por defecto y que nos
ayudarán a acelerar nuestro desarrollo de código y como siempre, a simplificar nuestro
código. Así que en el siguiente capítulo profundizaremos en cómo funcionan estas
herramientas y cómo las podemos usar en nuestro camino del desarrollo de código.

¡Vamos con todo!

_ 2

www.desafiolatam.com
Properties y cómo acceder a ellas
Las propiedades son los valores que componen una clase y pueden ser declarados como
mutables (var) o inmutables (val).

Vamos a utilizar como ejemplo la clase Beer que tiene 3 propiedades: name, type y grades.

class Beer(var name: String, var tipo: type, var grades: Float)

Para acceder a las propiedades se referencia directamente el nombre de la propiedad:

fun main() {
val beer = Beer("Gulden Draak", "Belga", 10.1)
println("La cerveza ${beer.nombre} tiene ${beer.grados} grados.")
}

Los getters y setters son opcionales y generalmente son declarados cuando el tipo de la
propiedad no es especificado o cuando debe ser calculado.
En el siguiente ejemplo, la propiedad isEmpty de tipo Boolean es calculada usando size de
la misma clase:

class MyList {
private val size = 0

val isEmpty: Boolean


get() = this.size == 0
}

En el caso de que el tipo de la propiedad no sea especificado se deben implementar


getter/setter.

Al definir la propiedad inmutable a de tipo Int indicando que puede ser nulo, el compilador
indica que la propiedad debe ser inicializada o ser declarada abstracta, por lo que no se
puede inferir el tipo.

val a : Int?

_ 3

www.desafiolatam.com
Para solucionarlo se implementa get y set que serán los encargados de indicar el tipo.

val a : Int?
get() {
TODO()
}
set(value) {}

De esta forma, la variable a tiene declarados los modificadores de acceso particulares que
deben ser implementados.

TODO () es una función propia del lenguaje que lanza siempre una excepción
NotImplementedError para indicar que la funcionalidad no ha sido implementada aún.

Inicialización tardía de propiedades y variables


La palabra clave lateinit se traduce como inicialización tardía y es útil cuando las
propiedades declaradas como de tipo no nulo deben inicializarse en el constructor pero el
desarrollador está seguro de que la variable no será nula al accederla, evitando así las
comprobaciones de nulidad cuando se utilice en el futuro.

Normalmente, las propiedades declaradas como de tipo no nulo deben inicializarse en el


constructor. Sin embargo, con bastante frecuencia esto no es conveniente.

Algunos de los casos dónde es extremadamente útil lateinit son:

● Variables que son inicializadas durante el ciclo de vida de Android.


● Utilización de inyección de dependencias ( DI ) donde las variables son inicializadas
fuera e independientemente del constructor, por ejemplo Dagger.
● Configuración para pruebas unitarias: las variables de entorno de prueba se
inicializan en las pruebas usando la anotación @Before

Para utilizar lateinit se deben cumplir ciertos requisitos:

● Tiene que ser una propiedad var (mutable), val no está permitido.
● Puede ser una propiedad dentro del cuerpo de una clase o una propiedad de nivel
superior (desde la versión 1.2 de Kotlin).
● Solo puede ser de tipo no nulo.
● Los tipos primitivos no están permitidos.

_ 4

www.desafiolatam.com
Un caso común es la utilización de lateinit en la construcción de test unitarios. El
siguiente ejemplo corresponde a la documentación oficial de Kotlin

public class MyTest {


lateinit var subject: TestSubject

@SetUp fun setup() {


subject = TestSubject()
}

@Test fun test() {


subject.method() // dereference directly
}
}

La variable subject es declarada como mutable y tiene en su definición la inicialización


tardía. Al ejecutarse la función setup se instancia la variable subject antes de hacer la
ejecución del test.

Para finalizar con las propiedades los invitamos a ver la documentación oficial de Kotlin
dónde se expone profundamente la utilización de propiedades.

_ 5

www.desafiolatam.com
Null Safety

¿Qué es un error de null?

Null (nulo en español) es literalmente un valor vacío. Al inicializar una variable en Java y
asignarle un valor, por defecto la variable queda con valor null. Por ejemplo:

public class Main {


String first;
}

Por defecto, la variable first tiene un valor nulo que sería equivalente a un valor vacío. Por
eso cuando una variable es nula y tratamos de hacer alguna operación sobre ella, ocurre un
NullPointerException, ya que esa variable no tiene un valor definido y por ende no podríamos
calcular el largo del String por ejemplo.

Kotlin es un lenguaje de programación que para mejorar la calidad y seguridad del software,
y para evitar excepciones en tiempo de ejecución y mejorar la estabilidad de la aplicación
incluye los tipos Nullable y Non-Null.

En Kotlin las variables son por defecto de tipo non-null. Esto significa que no pueden ser
asignadas con el valor null.

Por ejemplo el siguiente código es marcado con error al asignarlo como vacío:

// declara palabra con valor inicial abc


var palabra: String = "abc"

// Se indica un error al asignar null


palabra = null

Obtenemos el mismo error al inicializar directamente la variable:

//Se indica un error al asignar null


var palabra2: String = null

El mensaje de error "Null can not be a value of a non-null type String" indica que no se puede
asignar el valor null a un tipo no-nulo.

_ 6

www.desafiolatam.com
Es responsabilidad del programador indicar explícitamente que se quiere manejar una
variable nullable (con la posibilidad de que contenga null) agregando ? a la definición de la
variable.

// Se declara la variable como nullable agregando ? para luego asignarle


null
var palabra: String? = "abc"
palabra = null
//Se declara como nullable y se asigna null
var palabra: String? = null

De esta manera somos conscientes de que esa variable es null bajo nuestro propio riesgo.
Dado que la variable puede ser nula, se debe verificar primero si es null y manejar los 2 flujos
en forma separada.

fun imprimirLargoPalabra() {
var palabra: String? = "Kotlin"
if(palabra != null && palabra.length > 0) {
println("El largo de la palabra es de ${palabra.length}
caracteres")
} else {
// Alguna acción
}
}

Llamadas seguras (safe calls)

La verificación de variables nullables es uno de los aspectos pendientes en Java por lo


extenso del código de verificación y que en Kotlin es solucionado agregando el operador de
llamadas seguras, escribiendo ?. junto con el nombre de la variable. Por ejemplo:

fun imprimirLargoPalabra() {
var palabra: String? = "Kotlin"
println(palabra?.length})
}

_ 7

www.desafiolatam.com
El resultado de la ejecución es la longitud de la palabra (6 caracteres). Por otro lado, si
palabra fuera null, el resultado de la ejecución del siguiente código sería null, sin generar
un NullPointerException.

fun imprimirLargoPalabra() {
var palabra: String? = null
println(palabra?.length})
}

Si no se utiliza el operador safe calls se tendrá como resultado un error de sintaxis indicando
only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String.
Esto indica que solo se permiten llamadas seguras (?.) o la afirmación de no nulo (!!.) en un
receptor anulable de tipo String.

Es posible concatenar las llamadas a variables nullables en forma encadenada. Por ejemplo:

class Perro {
var raza: Raza? = null
}

class Raza {
var nombre: String? = null
}

En este caso tenemos clases que están unidas, un Perro tiene raza y a la vez la Raza tiene
un nombre y ambas variables fueron definidas como nullables. Entonces si quisiéramos
obtener el nombre de la raza de un perro, deberíamos hacer lo siguiente.
var perro = Perro()
perro?.raza?.nombre

Como podemos ver, en este caso donde hay una serie de relaciones entre clases con otra
clases y parámetros, tendríamos que usar el operador `?`` en cada nivel a medida que
accedemos a la información. Ahora supongamos que en vez de usar ? usamos otro
operador

perro.raza!!.nombre

_ 8

www.desafiolatam.com
Operador !!
El operador no nulo !! convierte cualquier valor a un tipo non-null (no nulo) y lanza una
excepción si el valor es nulo. En el siguiente ejemplo, la variable palabra es nula y al invocar
la función length sobre el valor nulo se lanza una excepción del tipo
NullPointerException.

fun imprimirLargoPalabra() {
var palabra: String? = null
println(palabra!!.length})
}

Este operador aunque no lo parezca es muy útil e importante, ya que dado que Kotlin es un
lenguaje que no acepta variables nulas por defecto, hay veces que si definimos una variable
con el operador ? indicando que podría ser null y después necesitamos agregar esa
variable como parámetro de algún método, el IDE nos pedirá usar el operador !!, ya que
necesita que aseguremos que no será null.

Veamos el siguiente código de ejemplo:

var lista: ArrayList<String>? = null


adapter.setData(lista)

Imagen 7. Error de sintaxis.


Fuente: Desafío Latam.

Se sugiere agregar el operador !! ya que estamos asegurando que esta lista no estará
vacía. Esta es una de las formas en que se nos hace responsable del manejo de las
variables en Kotlin.

var lista: ArrayList<String>? = null


adapter.setData(lista!!)

_ 9

www.desafiolatam.com
Este es un detalle importante que tenemos que tener en cuenta cuando desarrollemos en
Android usando Kotlin.

¿Qué pasaría si necesitamos poner algún valor null dentro de una lista?

La verdad en Kotlin se ha pensado en todo, veamos un ejemplo.

val listaDeRazas: List<String?> = listOf("bulldog", "labrador", null,


"pitbull")

Usando el mismo operador ?, podemos definir que nuestra lista contendrá elementos del
tipo String (ArrayList<String?>) pero soporta null; maravillosamente simple.

Operador Elvis
Cuando tenemos una referencia nullable a una variable de nombre b podemos decir: "Si b no
es nula, se utiliza; de otra forma hay que usar algún valor no nulo"
En código se expresa de la siguiente manera:

val result: Int = if (b != null) b.length else -1

Además de la forma recién expuesta, es posible ocupar el operador Elvis utilizando el


símbolo ? para expresar la misma sentencia:

val result: Int = b?.length ?: -1

Si la parte a la izquierda de ? no es nula, el operador Elvis la retorna. De otra forma, retorna la


parte a la derecha de la expresión luego de los :

_ 10

www.desafiolatam.com
When
When es una sentencia que nos ayuda a controlar el flujo dentro de nuestra aplicación.
Cuando tenemos un caso en el que tenemos que existen muchos valores posibles a
verificar, usar muchos if y else seguidos puede volverse difícil de leer. Para estos casos,
when es excelente herramienta.

La sentencia when, tiene la siguiente estructura:

when (x){
1 -> print("x == 1")
2 -> print("x == 2")
else -> print("x != 1 && x!= 2")
}

When permite manejar múltiples if/else de forma ordenada. Por ejemplo, un control de flujo
para imprimir un valor dada la evaluación de la variable numero, sería de esta forma:

if (numero == 0) {
println("número inválido")
} else if (numero == 1 || numero == 2) {
println("número muy bajo")
} else if (numero == 3) {
println("número correcto")
} else if (numero == 4) {
println("número alto, pero aceptable")
} else {
println("wow!!")
println("número muy alto")
}

_ 11

www.desafiolatam.com
Al introducir la instrucción when se indica directamente la acción para cada valor en
particular, incluso agrupando valores como en 1, 2 -> println("numero muy bajo"). Se
evaluará para cada caso el valor de la variable numero hasta que la condición sea cumplida.

when(numero) {
0 -> println("número invalido")
1, 2 -> println("número muy bajo")
3 -> println("número correcto")
4 -> println("número alto, pero aceptable")
else -> {
println("wow!!")
println("número muy alto")
}
}

Como podemos ver, con la instrucción when se ve un código mucho más legible y simple,
ponemos al inicio nuestra variable y luego podemos solo la condición que evaluamos y
después de -> ponemos las acciones a hacer en esa condición.
Además al utilizar llaves { } como en el else del ejemplo, se pueden introducir más de una
instrucción y programar lógicas más complejas.

Además de evaluar para múltiples valores permite retornar el valor y asignarlo en una
variable.

val check = true

val result = when(check) {


true -> println("it's true")
false -> println("it's false")
}

A la variable inmutable val result se le asigna el valor de retorno luego de la ejecución de


when.

_ 12

www.desafiolatam.com
When también permite la evaluación de rangos de forma simple:

var result = when(number) {


0 -> "número inválido"
1, 2 -> "número muy bajo"
3 -> "número correcto"
in 4..10 -> "número alto, pero aceptable"
else -> "número muy alto"
}

Además permite evaluar el tipo de la variable y tomar una decisión:

when (x) {
is Int -> print("es un entero")
is String -> print("Es un String")
is IntArray -> print("Es un arreglo de enteros")
}

La primera condición is Int evalúa si la variable x es del tipo Int. La segunda condición si es
del tipo String y la última si es un IntArray o arreglo de Int.

_ 13

www.desafiolatam.com

También podría gustarte