Categories: Empezando

Modismos

Share

Vamos a ver una colección de modismos que se utilizan con frecuencia.

Crear DTOs (POJOs/POCOs)

//sampleStart
data class Persona(var nombre: String, var email: String)
//sampleEnd

fun main() {
    val persona = Persona("Pepe", "pepe@email.com")
    println("El nombre es ${persona.nombre}")
    persona.email= "jose@gmail.com"
    println("El nuevo email es ${persona.email}")
}

Con esa sola línea obtendríamos:

  • getters (y setters en caso de utilizar var) de todas las propiedades
  • equals()
  • hashCode()
  • toString()
  • copy()
  • component1(), component2(), …, para todas las propiedades (Ver Clases de Datos)

Valores por defecto de los parámetros de una función

//sampleStart
fun ejemplo(numero: Int = 0, texto: String = "Vacio")
 = println("El numero es $numero y el texto es $texto")
//sampleEnd

fun main() {
    ejemplo()
    ejemplo(100,"hola")
}

Filtrar una lista

fun main() {
//sampleStart
val lista = listOf(-2,-1,0,1,2,3)
println("Lista sin filtrar: $lista")

val numerosPositivos = lista.filter { x -> x > 0 }
println("Lista filtrada: $numerosPositivos")
//sampleEnd
}

O una alternativa incluso más corta utilizando it:

fun main() {
val lista = listOf(-2,-1,0,1,2,3)
println("Lista sin filtrar: $lista")

//sampleStart
val numerosPositivos= lista.filter { it > 0 }
//sampleEnd
println("Lista filtrada: $numerosPositivos")
}

Interpolación de textos

fun main() {
//sampleStart
    val nombre = "Javier"
    println("Su nombre es $nombre") // "Su nombre es Javier"
//sampleEnd
}

Controles de instancia

class Persona(val nombre: String)
class Coche(val marca: String)

val persona = Persona("Juan")
val coche = Coche("SEAT")

//sampleStart
fun controlInstancia(parametro: Any) {
    when (parametro) {
        is Persona -> println("Es una persona cuyo nombre es ${parametro.nombre}")
        is Coche -> println("Es un coche de la marca ${parametro.marca}")
        else -> println("Desconocido")
    }
}
//sampleEnd

fun main() {
    controlInstancia(persona) // "Es una persona"
    controlInstancia(coche) // "Es un coche"
    controlInstancia("hola") // "Desconocido"
}

Recorrer un mapa/lista de pares

fun main() {
//sampleStart
    val mapaPersonaCoche = mapOf("Juan" to "SEAT", "Pedro" to "Opel")
    for ((k, v) in mapaPersonaCoche) {
        println("$k -> $v")
    }
//sampleEnd
}

Alternativamente también podríamos hacerlo así:

fun main() {
//sampleStart
    val mapaPersonaCoche = mapOf("Juan" to "SEAT", "Pedro" to "Opel")
    for (map in mapaPersonaCoche) {
        println("${map.key} -> ${map.value}")
    }
//sampleEnd
}

Intervalos

fun main() {
//sampleStart
    val lista = mutableListOf<Int>()

    for (i in 1..10) lista.add(i)
    println(lista).also { lista.clear() }

    for (i in 1 until 20) lista.add(i)
    println(lista).also { lista.clear() }

    for (x in 2..10 step 2) lista.add(x)
    println(lista).also { lista.clear() }

    for (x in 10 downTo 1) lista.add(x)
    println(lista).also { lista.clear() }

    val x = 3
    if (x in 1..10) print("Está en el intervalo") // Evita anidar 'if/for' colocando el intervalo en el 'if'
//sampleEnd
}

Como puedes ver, he utilizado .also para que una vez que se haya mostrado la lista se limpie a posteriori. Observa también que aunque la lista es val, es decir, no podrás hacer lista = otraList pero si podrás modificar sus parámetros ya que es una MutableList.

Listas

fun main() {
//sampleStart
    val lista = listOf("a", "b", "c")
    val listaMutable = mutableListOf("a", "b", "c").apply {
        add("d")
        remove("b")
    }
//sampleEnd
    println(lista)
    println(listaMutable)
}

Con .apply podemos utilizar varias funciones sobre el mismo objeto sin tener que escribirlo con cada función. Es muy útil cuando ya que además de ahorrarte código duplicado facilita su lectura.

Mapas

fun main() {
//sampleStart
    val mapa = mapOf("a" to 1, "b" to 2, "c" to 3)
//sampleEnd
    println(mapa)
}

Como hemos dicho antes, en Kotlin puedes utilizar las variantes mutables de ciertas interfaces. Como ejemplo, las listas o los mapas tienen su variante mutable,

fun main() {
//sampleStart
    val mapa = mutableMapOf("a" to 1, "b" to 2, "c" to 3)
    println(mapa["a"]) // "1"

    mapa["a"] = 10 // Utilizamos mutableMapOf para poder modificar el valor
    println(mapa["a"]) // "10"
//sampleEnd
}

Como puedes ver, aunque utilizamos val podemos modificar los valores de cada clave. Si añadiésemos un nuevo valor también funcionaría:

fun main() {
    val mapa = mutableMapOf("a" to 1, "b" to 2, "c" to 3)
//sampleStart
    mapa["e"] = 4
    println(mapa["e"]) // "4"
//sampleEnd
}

Sin embargo si tratásemos de igualar mapa a otro mapa diferente, no podríamos compilar:

fun main() {
//sampleStart
    val map = mapOf("a" to 1)
    val otroMap= mutableMapOf("b" to 2)
    map = otroMap
//sampleEnd
}

Atributo tardío (Lazy)

Cuando utilizas by lazy lo que haces es que la variable no se inicie en el momento en el que la declaras. Se inicia en el momento en el que se usa.

//sampleStart
val texto: String by lazy {
   "lazy property!"
}
//sampleEnd

fun main() {
    println(texto) // Ahora se inicia la variable 'texto'
}

Funciones de extensión

Esta es una de las características que más me gustan de Kotlin. Puedes añadir comportamientos o funcionalidades nuevas a cualquier clase. Por ejemplo vamos a añadir a String una función que invierta la cadena de texto que le pasemos.

//sampleStart
fun String.invertirTexto(): String {
    var textoInvertido = ""
    for (i in (this.length - 1 downTo 0)) {
        textoInvertido = textoInvertido + this.get(i)
    }
    return textoInvertido
}
//sampleEnd

fun main() {
    val texto = "aniram al ne etatsíla"
    println(texto.invertirTexto()) // Mostraría 'Alístate en la marina'
}

Un ejemplo de esto aplicado a Android sería crear una función para añadir una nueva funcionalidad a un ImageView: Descargar imágenes de Internet con Picasso o Glide.

fun ImageView.loadUrl(url: String) {
    Picasso.with(context).load(url).into(this)
}

imageView.loadUrl(url) // Bye bye boilerplate!

He creado un repositorio en GitHub con una recopilación de estas funciones. Puedes sugerirme más mediante pull requests/issues o dejando un comentario en esta entrada para añadir más.

Crear un Singleton

//sampleStart
object Recurso {
    val nombre = "Juan"
}
//sampleEnd

fun main() {
    println(Recurso.nombre) // "Juan"
}

También es posible crear un objeto anónimo:

fun main() {
//sampleStart
    val recurso = object {
        val nombre = "Pepe"
    }
//sampleEnd
    println(recurso.nombre) // "Pepe"
}

Abreviación de “si no es nulo”

Imagina que tratas de obtener una lista de objetos de una API, y por algún motivo no puede obtener la lista, obteniendo una lista null, para evitar un error simplemente utilizaríamos ? de esta forma:

fun main() {
//sampleStart
    val listaNull: List<String>? = null // Simulamos obtener una lista vacia
    println(listaNull?.size) // Compilaría y mostraría 'null'
//sampleEnd
}

Abreviación de “si no es nulo entonces”

También conocido como Elvis operator por su forma ?:

fun main() {
//sampleStart
    val listaNull: List<String>? = null
    println(listaNull?.size ?: "Lista vacia") // "Lista vacia"
//sampleEnd
}

Obtener el primer ítem de una lista que puede estar vacía

fun main() {
//sampleStart
    val listaNull: List<String> = listOf()
    println(listaNull.firstOrNull()) // "null"
//sampleEnd
}

Ejecutar si no es nulo

En el siguiente caso como la lista será nula, no imprimirá el texto, pero tampoco obtendremos una excepción. Esto es realmente útil en Android ya que muchas veces tenemos ciertos elementos que nunca sabemos si son nulos o no como el contexto en un fragmento. Con un símbolo de interrogación evitamos tener que colocar el clásico if (elemento != null) ...

fun main() {
//sampleStart
    val listaNull: List<String>? = null
    listaNull?.let { println("La lista está vacía") }
//sampleEnd
}

Abreviación de “devolver cuando (when)”

//sampleStart
fun obtenerColorPorID(color: Int): String {
    return when (color) {
        0 -> "Rojo"
        1 -> "Verde"
        2 -> "Azul"
        else -> "Desconocido"
    }
}
//sampleEnd

fun main() {
    val color = obtenerColorPorID(1)
    println(color) // "Verde"
}

Expresión ‘try/catch’

//sampleStart
fun mostrarCoche() {
    val coche = try {
        "SEAT"
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e)
    }
    println(coche)
}
//sampleEnd

fun main() {
    mostrarCoche() // Si no hay ningún error mostraría "SEAT"
}

Expresión ‘if’

//sampleStart
fun obtenerColorPorID(marca: Int) {
    val color = if (marca == 1) "Rojo" else "Verde"
    println(color)
}
//sampleEnd

fun main() {
    obtenerColorPorID(1) // "Rojo"
}

Uso de métodos de estilo constructor

//sampleStart
fun rellenarDeAes(tamaño: Int): CharArray {
    return CharArray(tamaño).apply { fill('A') }
}
//sampleEnd

fun main() {
    val charArrayAes = rellenarDeAes(4)
    for (i in 0 until charArrayAes.size) print("(${i + 1}, ${charArrayAes[i]}) ")
}

Funciones de expresión única

La siguiente función:

//sampleStart
fun nombre() = "Juan"
//sampleEnd

fun main() {
    println(nombre()) // "Juan"
}

Es equivalente a:

//sampleStart
fun nombre(): String {
    return "Juan"
}
//sampleEnd

fun main() {
    println(nombre()) // "Juan"
}

Estas funciones pueden ser combinadas con otros modismos, por ejemplo con un when

//sampleStart
fun obtenerColorPorID(color: Int): String = when (color) {
    0 -> "Rojo"
    1 -> "Verde"
    2 -> "Azul"
    else -> "Desconocido"
}
//sampleEnd

fun main() {
    println(obtenerColorPorID(2)) // "Azul"
}

Utilizar múltiples métodos de una instancia de objeto con ‘with’

Para evitar tener que escribir varias veces el mismo código y evitar duplicados, puedes utilizar todos los métodos de un objeto gracias a with:

class Coches {
    fun seat() = "SEAT"
    fun opel() = "OPEL"
    fun bmw() = "BMW"
}

fun main() {
    val coches = Coches()
//sampleStart
    with(coches) {
        val listaDeCoches = listOf(seat(), opel(), bmw())
        println(listaDeCoches)
    }
//sampleEnd
}

Recent Posts

  • Curso Interactivo

Variables

En esta lección aprenderás a declarar variables y los tipos básicos.

5 años ago
  • Curso Interactivo

Introducción al Curso Interactivo

La mejor forma de aprender algo en esta vida es a base de practicar. Espero…

5 años ago
  • Coroutines

Iniciar una Corrutina

La principal forma de iniciar una corrutina en Kotlin es con el coroutine builder launch…

5 años ago
  • Coroutines

Coroutines

Las coroutines en Kotlin vienen a tratar de solucionar todos los problemas y dificultades que…

5 años ago
  • Funciones Estándar

Resumen Elección de Modismo

Con este esquema te puedes guiar a la hora de elegir el modismo o función…

5 años ago
  • Funciones Estándar

With

El último que queda por ver es with qué en inglés significa "con". Por lo…

5 años ago