Views: 5555201 words0 Comments on KotlinPublished On: junio 8th, 2022Last Updated: agosto 21st, 2022By

lestrades

Kotlin Lenguaje de programación

Es un lenguaje de programación de tipado estático que corre sobre la máquina virtual de Java y que también puede ser compilado a código fuente de JavaScript. Es desarrollado principalmente por JetBrains en sus oficinas de San Petersburgo. Wikipedia.
Diseñador: JetBrains.
Apareció en: 2016.
Licencia: Apache 2.
Paradigma: Orientado a objetos.
Sistema de tipos: Estático.
Sistema operativo: cualquiera que soporte la JVM o tenga un intérprete de Javascript.
Lenguajes: Java, Kotlin.

Algunas dudas:

Si una función literal (expresión lambda) sólo tiene un parámetro, su declaración puede ser omitida (junto con el ->) y su nombre será it. Por tanto it es una convención para que la declaración de las funciones lambda sea aún mas breve.

En Kotlin, cada constructor secundario debe invocar al constructor primario—utilizamos la palabra reservada this para lograrlo.

class Book {
    var title: String
    var isbn: Long
 
    constructor(title: String, isbn: Long) {
        this.title = title
        this.isbn = isbn
    }
}

Objeto de contexto: this o it
Dentro de la lambda de una función de alcance, el objeto de contexto está disponible mediante una referencia corta en lugar de su nombre real. Cada función de alcance utiliza una de dos formas de acceder al objeto de contexto: como un receptor lambda ( this ) o como un argumento lambda ( it ). Ambos proporcionan las mismas capacidades, por lo que describiremos los pros y los contras de cada uno para diferentes casos y brindaremos recomendaciones sobre su uso.

fun main() {
    val str = "Hello"
    // this
    str.run {
        println("The receiver string length: $length")
        // println ("La longitud de la cadena del receptor: $ {this.length}") // hace lo mismo
    }

    // it
    str.let {
        println("The receiver string's length is ${it.length}")
    }
}

Se puede ver el contenido original en la página runebook.dev.

Es el interfaz global de información acerca del entorno de la aplicación. Es una clase abstracta que implementa Android. Permite acceder a los recursos específicos de la aplicación y a sus clases, así como llamar al padre para realizar operaciones a nivel de la aplicación, como lanzar Activities, difundir mensajes por el sistema, recibir Intents, etc.

En la página Jarroba.com Ramón Invarato nos lo define más a fondo.

De donde obtenemos el contexto:

  • getApplicationContext(): permite obtener el contexto de su aplicación.
  • getContext(): permite obtener el contexto en el que se ejecuta la vista actual.
  • getBaseContext(): permite obtener el contexto definido mediante el método setBaseContext().
  • this: (sólo cuando se encuentre en una clase que herede de forma directa o indirecta de la clase Context)

Páginas de ayuda:

Canales:

A los que agradezco parte de mi formación y que me han ayudado a entender varios conceptos y dudas que se han presentado y que se presentan aún en el día a día como programador.
  • Codigo Online – Canal de programación donde veremos de manera simple y sencilla como aprender a programar. Destinado a todas aquellas personas que nunca se han atrevido a programar y quieren dar ese gran salto.

  • DevExperto – Antonio Leiva -En mi canal encontrarás todo tipo de contenido relacionado con el mundo del desarrollo móvil en Android: desde tutoriales a entrevistas, pasando por noticias, curiosidades, sesiones de preguntas y respuestas en directo y mucho más.

  • MoureDev by Brais Moure – Tutoriales de PROGRAMACIÓN y DESARROLLO de APLICACIONES iOS y Android. Aprende a crear Apps con Android Studio, Kotlin, Jetpack Compose, Xcode, Swift, SwiftUI, Firebase, Flutter y mucho más….

  • Programación Android by AristiDevs – Soy Aris, desarrollador de aplicaciones móviles desde hace más de 6 años y en este canal aprenderás a crear apps de una forma sencilla, amena y totalmente gratuita. Cada semana un vídeo y un artículo nuevo en https://cursokotlin.com para que te sea más sencillo seguir los tutoriales.

  • Pildorasinformaticas – Este canal pretende compartir conocimientos informáticos entre todos los integrantes de la comunidad Internet. Se tratarán diversas materias, desde ofimática básica y avanzada hasta programación, pasando por diseño gráfico y web.

  • Códigofacilito  – Código Facilito es una de las plataformas de aprendizaje online de programación más grandes de habla hispana. Desde el 2010 formamos programadores en toda América Latina y España enseñando. HTML, JavaScript, React, Python, Rails, Go y mucho más.

  • Variables y constantes:

//Texto
val char: Char = 'c'// Caracter.
val string: String = "Lestrades" // texto.
//Boolean
val boolean: Boolean = true // true o false.
//Numérico entero
val trabajos: Byte = 3 // 8 bit De -128 a 127
val dias: Short = 200 // 16 bits -32768 a 32767
val minutos: Int = 4800 // 32 bits
val segundos: Long = 480000000 // 64 bits
//Númerico con coma flotante.
val altura: Double = 1.75f // 32 bits
val altura2: Float = 1.753333333F // 64 bits
val name = "Juan" // Con val no se puede cambiar el valor.
var age = 30 //Con var se puede cambiar el valor.
var apellido:String // Declara una variable de un tipo sin asignarle valor.
//Las constantes normalmente se le pone el nombre en mayúscula.
const val GENERO = masculino // Declaracion de una constante.

Para añadir una variable a un texto (String Template)

println("Mi nombre es $name")
println("Altura ${altura}m") salida ==> Altura 1.75m
var obj: Any = "Kotlin course"
val objNum: Any = 3
fun main() {
    val b= 3
    val objNum: Any = 3//"3d"
    if (objNum is Int) {
        println("objNum es un número")
        println(objNum.toString().toInt() * b)
    } else {
        println("objNum no es un número")
    }
}
/* Salida===>
objNum es un número
9
*/
var nullStr: String? = null // sin el ? da error.
//Para que podamos aplicar métodos además de tener una variable nula,
//tenemos que ponerle el ? para que no nos de error.
println(nullStr?.get(0))//Como es null no se ejecuta lo de después del interrogante.
//Se utiliza para decirle a Kotlin que la variable fijo que no es null
var variable :String = "hola"
if (variable != null){
   variable!!.get(0)
}
/* Salida===> h
*/

El operador Elvis es parecido a una sentencia If pero simplemente considera si el valor es nulo devuelve el valor añadido al final.

fun main() {
    var nulo :String? = null
    var elvis : String? = nulo
    println(elvis)
    var elvis2 = nulo ?: "Lestradamus"
    println(elvis2)
   }
/* Salida===>null
             Lestradamus
*/
fun main() {
    var numero:Any = 3
    var texto:Any = "tres"
    esEntero(numero)
    esEntero(texto)
    //Otra forma de intentar convertir de un tipo a otro sin que de error si no se pudiera
    val otraForma = numero as? String
       }
fun esEntero(dato:Any){
    if (dato is Int){
        println("$dato es un entero")
    } else{
        println("$dato no es un entero")
    }
}
/* Salida===>3 es un entero
             tres no es un entero
*/

Lazy: Esta variable global puede tener un algoritmo asociado de forma que cuando se ejecuta la primera vez, se guarda y siempre tendrá ese valor.

Lateinit: solo es aplicable a variables globales y en algún punto de nuestro código a de ser inicializada.

private lateinit var titulo:String
private val milisegundos:Long by lazy {
    System.currentTimeMillis()
}
fun main() {
    println(milisegundos)
    println(milisegundos)
    if (titulo()){
        println(titulo)
    }
}
private fun titulo(): Boolean{
    titulo = "Lestradamus"
    return titulo.isNotEmpty()
}
/* Salida===>1655393814421
             1655393814421
             Lestradamus
 */

  • Métodos y funciones :

//Sin argumentos
fun basic(){
    print("Hola")
} 
//Con argumentos
fun argumento(name: String) {
    println("hola")
}
//Retornando datos
fun suma(x:Int, y:Int): Int{
    return x + y
}
//Otra forma de hacer lo mismo que arriba pero abreviado
fun suma(x:Int, y:Int)= x + y
//Para cualquier clase de datos 
fun cualquierDato():Any {
    return "Datos retornados"
}
//Sin argumentos
basic()
// Con argumentos
argumento("Jose")
//Retornando datos
println(retornaDatos())
//Crear función automáticamente
funcion() 
// y damos ALT + Enter sobre el nombre " funcion() y 
// de la caja de opciones elegimos create function.
//Tener el mismo nombre de función pero con diferentes parámetros
fun overload(age: Int) {
    println("mi edad es: $age")
}
fun overload(trabajo: String){
    println("mi trabajo es: $trabajo")
}
fun overload (name: String, age: Int){
    println("Mi nombre es $name y tengo $age años")
}
//Arreglo de argumentos
fun varios(vararg varios: String){
println(varios[0])
println(varios[1])
println(varios[2])
}
//readline
    println("Inserte un número:")
    val first = readLine()
    val a = first!!.toInt()
    println("a = $a")

    println("Inserte otro número:")
    val second = readLine()
    val b = second!!.toInt()
    println("b = $b")
fun main() {
    // Lestradamus desarrollador
    val string = "Lestradamus Apuntes y más"
    val string2 = "Apuntes"
    println(string.length) //Longitud del texto
    //Nos dice las posiciones entre la L y La D ( 1e,2f,3g,4h,5i,6j,7k,8l)
    println(string.compareTo(string2))
    //Nos dice si son iguales las cadenas de texto
    println(string.equals(string2))
    println("Apuntes".equals(string2))
    println("Contiene: ${string.contains(string2)}")
    println(string.lowercase())//Convierte en minúsculas
    println(string.uppercase())//Convierte en mayúsculas
    println(string.subSequence(0,11))//Imprime un rango
    //Da la posición de la primera "a" que encuentra
    println(string.indexOf("a"))
    //Da la posición de la última letra "a" que encuentra
    println(string.lastIndexOf("a"))
    println(string.isBlank())//Nos evalua si contiene caracteres
    println(string.isEmpty())//Evalua si esta vacio, si hay un espacio da false
    println(string.replace("a","i"))//===>Lestridimus Apuntes y más
    println(string.replaceBefore("Lestradamus","Lestrad "))//===>Lestrad Lestradamus Apuntes y más
    println(string.reversed())//===>sám y setnupA sumadartseL
    println(string.slice(11..string.length-1))//===> Apuntes y más
    println(string.split(" "))//===>[Lestradamus, Apuntes, y, más]
    println(string.startsWith("L"))//Determina si el string empieza con L
    println(string.substring(12,18))//===>Apunte
    val hola = "    Hola  "
    println(hola.trim())//Quita los espacios del principio y final de la cadena
}
// Se pueden concaternar varios métodos a la vez
  • (with) Nos evita repetición de código, se utiliza para llamar métodos con respecto a un determinado objeto:
fun main() {
   var titulo = "Lestradamus"
    //nos evita tener que repetir titulo en cada sentencia
    with(titulo){
        println(lowercase())// Sin with titulo.println(lowercase())
        println(uppercase())// Sin with titulo.println(uppercase())
        println(reversed())//Sin with titulo.println(reversed())
    }
}
/* Salida===>lestradamus
             LESTRADAMUS
             sumadartseL
*/
  • (apply) Se utiliza para modificar el valor de las propiedades en el objeto.
private data class coche(
    var modelo: String = "Seat",
    var peso: Int = 1100,
    var color: String = "Rojo"
)
fun main() {
    var miCoche = coche()
    miCoche.modelo= "x"
    miCoche.peso=0
    miCoche.color = "x"
    //de esta forma nos evitamos poner miCoche en cada línea
    miCoche.apply {
        modelo = "Honda"  // miCoche.modelo = "Honda"
        peso = 1500       // miCoche.peso = 1500
        color = "Azul"    // miChoche.color = "Azul"
    }
    println(miCoche)
}
/* Salida===>coche(modelo=Honda, peso=1500, color=Azul)
 */
  • (run) Permite hacer un bloque de comandos asignados a un objeto:
fun main() {
    val titulo = "Lestrades".run {
        print("$this al reves y en mayúsculas es: ")
        uppercase ().reversed()
    }
    println(titulo)
    val computo = run {
        val a = 2
        val tempA = 35
        val tempB = 40
        (tempA + tempB) / a
    }
    print(computo)
}
/* Salida===>Lestrades al reves y en mayúsculas es: SEDARTSEL
             37
 */
  • (let) Se recomienda para ejecutar un bloque de código cuando un objeto puede ser nulo, (let) lo verifica y para mapear.
fun main() {
    val titulo: String? = null
    val copiaTitulo = titulo?.let {
        println(titulo)
        //esto se ejecuta si titulo no es null
    }
    println(copiaTitulo)
    //otra funcionalidad
    val presupuesto = Lineas("Lestradamus",
        listOf(Linea(50.0),Linea(80.0),Linea(230.0)
        )
    )
    val total = presupuesto.let { 
        val coste = it.lineas.sumOf { 
            it.precio
        }
        "El precio es de: $coste"
    }
    println(total)
}
class Linea(val precio: Double)
class Lineas(val empresa: String, val lineas: List)
/* Salida===>null
             El precio es de: 360.0
 */
  • (also) El objetivo es permitirte añadir acciones adicionales sobre un objeto. Su uso se traduce a «y también hacer lo siguiente con el objeto»
fun main() {
    val presupuesto = Lineas("Lestradamus",
        listOf(Linea(50.0),Linea(80.0),Linea(230.0)
        )
    )
    val total = presupuesto.let {
        val coste = it.lineas.sumOf {
            it.precio
        }
        "El precio es de: $coste"
    }.also { println(it) }

}
class Linea(val precio: Double)
class Lineas(val empresa: String, val lineas: List)
/* Salida===>El precio es de: 360.0
 */

Se usa para añadir una función a cualquier clase, independientemente que tengamos acceso a su código o no.

//fun Clase.nombreFuncion(nombreParametro:Tipo){ Argumentos}
// Ejemplo
fun Context.toast(message: String, length: Int = Toast.LENGTH_LONG) {
    Toast.makeText(this, message, length).show()
}

La estructura de una lambda es : lambda:(X,Y)->Z

La lambda siempre devuelve la última linea de su bloque

Un ejemplo:

sum:(Int,Int)->Int
//Se definen los tipos de entrada y el tipo de salida

fun test(){
    val sum:(Int,Int)->Int = {x,y->x+y}
    //Otra forma de hacerlo
    val suma = {x: Int, y: Int -> x + y}
    //operaciones con la función operación
    val res = operacion(5,8){x,y->
        x-y
    }//Salida ==> -3
}
//Esta función deja hacer cualquier operación con dos enteros
fun operacion(x:Int,y:Int, op:(Int,Int)->Int)= op(x,y)
//Usar una función como una lambda
fun sum(x: Int,y: Int): Int = x +y
val res = operacion(5,8,::sum) //Salida ==> 13

Lambdas con receivers:

fun  T.apply(body: T.() -> Unit): T {
    this.body()
    return this
}

fun <T, U> T.run(body: T.() -> U): U {
    return this.body()
}

fun <T, U> T.let(body: (T) -> U): U {
    return body(this)
}

fun <T, U> witch(receiver: T, body: T.() -> U): U {
    return receiver.body()
}
fun  T.also(body: (T)-> Unit): T{
    body(this)
    return this
}

La palabra reservada infix permite llamar a una función con la notación de infijo, es decir, la capacidad de insertar la invocación de la función entre dos operandos con el fin de expresar la operación. Develou.com

Ya tenemos varias funciones infix:

fun prueba(){                                                                                       
    //until es una funcion infix, es usada para elegir un rango                                     
    // desde el número que se pone anterior a until hasta uno menos del número posterior.           
    for (i in 0 until 10)   {                                                                       
                                                                                                    
    }                                                                                               
    //to es una funcion infix                                                                       
    val map = mapOf("a" to 1, "b" to 2)                                                             
}                                                                                                   
//Se crean como una función de extensión pero anteponiendo la palabra infix,de la siguiente manera: 
infix fun Int.until2(to: Int): IntRange {                                                           
    if (to <= Int.MIN_VALUE) return IntRange.EMPTY                                                  
    return this .. (to - 1).toInt()                                                                 
}

  • Bucles, condicionales y manejo de errores:

if (true) {
println("Es verdad")
}
val nombre = "Lestrades"
if (nombre.equals("lestrades")) {
println("Es verdad")
}
// != diferente; && = and; || = or
if (nombre != "Lestrades" && nombre != "Jose") {
println("No eres Lestrades")
} else {
println("Eres Lestrades")
}
val nombre = "Lestrades"
when (nombre){
   //Si nombre es igual a Lestrades o a Jose
   "Lestrades", "Jose" -> println("Hola Lestrades")
   //Si nombre es igual a amigo
   "Amigo" -> println("Hola amigo")
   //Si no es igual a ninguna de las opciones
   else -> println("Hola desconocido")
}
fun main() {
    listado("Lestrades","Jose","Paco","Ana")
}
fun listado(vararg nombres:String){
    println("Lista del 1 al 10")
    for (i in 1..10) print(" $i")
    println("")
    println("Lista del 1 al 10 de 2 en 2")
    for (i in 1..10 step 2) print(" $i")
    println("")
    println("Imprime el listado")
    for(i in 0..nombres.size -1){
        println("$i = ${nombres.get(i)}")
    }
    //otra forma de hacerlo
    for (nombre in nombres){
        println(nombre)
    }
}
/* Salida===>
Lista del 1 al 10
 1 2 3 4 5 6 7 8 9 10
Lista del 1 al 10 de 2 en 2
 1 3 5 7 9
Imprime el listado
0 = Lestrades
1 = Jose
2 = Paco
3 = Ana
Lestrades
Jose
Paco
Ana
*/
fun main() {
    listado("Lestrades","Jose","Paco","Ana")
}
fun listado(vararg nombres:String){
    nombres.forEach{
        println(it)
    }
    //Podemos renombrar el it para que sea más descriptivo
    println("----Otra forma----")
    nombres.forEach{ nombre ->
        println(nombre)
    }
    println("--Rangos--")
    //Imprimir rangos
    (1..5).forEach {
        print(" "+ it)
    }

}
/* Salida===>
Lestrades
Jose
Paco
Ana
----Otra forma----
Lestrades
Jose
Paco
Ana
--Rangos--
 1 2 3 4 5
*/
fun main() {
    listado("Lestrades","Jose","Paco","Ana")
}
fun listado(vararg nombres:String){
    var indice = 0
    //mientras que el indice sea menor que el número de nombres
    while (indice < nombres.size){ println("Indice: $indice : ${nombres.get(indice)}") //Incrementamos el valor de indice indice++ } } /* Salida===>
Indice: 0 : Lestrades
Indice: 1 : Jose
Indice: 2 : Paco
Indice: 3 : Ana
*/
fun main() {
    listado("Lestrades","Jose","Paco","Ana")
}
fun listado(vararg nombres:String){

    var indice = nombres.size
    do {
        indice--
        println("Indice: $indice : ${nombres.get(indice)}")
    }while (indice > 0 )
}
/* Salida===>
Indice: 3 : Ana
Indice: 2 : Paco
Indice: 1 : Jose
Indice: 0 : Lestrades
*/
fun main() {
    (1..10).forEach {
        if (it==3){
            return
        }
        print(" $it")
    }
    println("")
    println("Acabó")
}
/* Salida===>
 1 2 
*/

Con el caso 1 cuando hacemos return directamente sale hasta de la función main.

Caso 2:

fun main() {
    (1..10).forEach {
        if (it==3){
            return@forEach
        }
        print(" $it")
    }
    println("")
    println("Acabó")
}
/* Salida===>
1 2 4 5 6 7 8 9 10
Acabó
*/
fun main() {
    for (i in 1..10){
        if (i==3){
            break
        }
        print(" $i")
    }
    println("")
    println("Acabó")
}
/* Salida===>
 1 2 
Acabó
*/

A diferencia con el Return, el Break solo sale del bucle, pero no de la función.

fun main() {
    var numero: Any = 3
    var texto: Any = "tres"
    try { //Sí estas sentencias tienen error
        println(numero.toString().toInt())
        println(texto.toString().toInt())
    } catch (e: Exception) { //Se ejecutan estas sentencias
        println(e)
        println("No se ha podido convertir")
    } finally {//Esto se ejecuta de todas formas
        println("Que tenga un buen día. :)")
    }
}
/* Salida===>java.lang.NumberFormatException: For input string: "tres"
             No se ha podido convertir
             Que tenga un buen día. :)
*/
fun main() {
    val texto = "Lestradamus"
    val numero= 1
    esEntero(numero)
    try {
        esEntero(texto)
    } catch (e: Exception) {
        println(e)
    } finally {
        println("Todo correcto")
    }

}
private fun esEntero(dato:Any){
    if (dato is Int){
        println("$dato es un entero")
    } else{
        throw TypeCastException("No es un entero")
    }
}
/* Salida===>1 es un entero
             kotlin.TypeCastException: No es un entero
             Todo correcto
 */

  • Estructuras de datos:

fun main() {
multiargumentos("Lestrades","Jose","Juan")
}
fun multiargumentos(vararg nombre: String){
    println("varag en la posición 1: ${nombre[0]}")
}
//Salida===>
//varag en la posición 1: Lestrades
fun main() {
    val array = arrayOf("Lestrad", "Paco", "Chema")
    println(array[0])//Imprime la posición 1
    //Otra manera de hacerlo
    println(array.get(1))//Imprime la posición 2
    //Saber cuantas posiciones tiene el array
    println(array.size)
}
/*
Salida===>
Lestrad
Paco
3
*/
fun main() {
    val listado = arrayOfNulls(3)//El 3 es el número de posiciones
    listado[1]= "Jose"
    println("posición 1: "+listado[1])
    println("posición 2: "+listado[2])
}
/*
Salida===>
posición 1: Jose
posición 2: null
*/
fun main() {
    val listado = listOf("Lestrades", "Paco", "Chema")
    println("Toda la lista: $listado")
    println("Posición 1 ${listado.get(0)}")
    //Otra forma de hacerlo
    val listado2:List
    listado2 = listOf("Lestrades", "Paco", "Chema")
    println("Posición 2 ${listado2.get(1)}")
}
/*
Salida===>
Toda la lista: [Lestrades, Paco, Chema]
Posición 1 Lestrades
Posición 2 Paco
*/
fun main() {
    val listado = mutableListOf("Lestrades", "Paco", "Chema")
    println("Toda la lista: $listado")
    listado.add("Luis")
    println("Toda la lista: $listado")
    listado.removeAt(1)// Elimino a Paco
    println("Elimino a Paco: $listado")
    listado.remove("Luis")//Elimino a Luis
    println("Elimino a Luis: $listado")
    listado.set(1,"Jose")//Cambio a Chema por Jose
    println("Cambio a Chema por Jose: $listado")

}
/*
Salida===>
Toda la lista: [Lestrades, Paco, Chema]
Toda la lista: [Lestrades, Paco, Chema, Luis]
Elimino a Paco: [Lestrades, Chema, Luis]
Elimino a Luis: [Lestrades, Chema]
Cambio a Chema por Jose: [Lestrades, Jose]
*/
fun main() {
    val listado = mutableMapOf<Int,String>()
    listado.put(1,"Lestrades")
    listado.put(2,"Jose")
    listado.put(18, "Ana")
    println("Toda la lista: $listado")
    println("Imprimir por clave: ${listado.get(2)}")
    listado.remove(2)
    println("Toda la lista: $listado")
    listado.set(18,"Jose")//Cambiar Ana por Jose
    println("Cambio Ana por Jose: $listado")
    //Imprimir solo las claves
    println(listado.keys)
    //Imprimir solo los valores
    println(listado.values)

}
/*
Salida===>
Toda la lista: {1=Lestrades, 2=Jose, 18=Ana}
Imprimir por clave: Jose
Toda la lista: {1=Lestrades, 18=Ana}
Cambiada Ana por Jose: {1=Lestrades, 18=Jose}
[1, 18]
[Lestrades, Jose]
*/

Otro ejemplo seria mapear un listado:

//Teniendo  una data class:
data class Fotos (val title: String, val url:String, val type :Type){                        
    enum class Type {PHOTO,VIDEO}                                                            
}                                                                                            
//Forma larga                                                                                
fun incluirFoto():List = listOf(                                                      
    Fotos("Title 1", "https://placekitten.com/200/200?image=1", Fotos.Type.PHOTO),           
    Fotos("Title 2", "https://placekitten.com/200/200?image=2", Fotos.Type.VIDEO),           
    Fotos("Title 3", "https://placekitten.com/200/200?image=3", Fotos.Type.PHOTO),           
    Fotos("Title 4", "https://placekitten.com/200/200?image=4", Fotos.Type.PHOTO),           
    Fotos("Title 5", "https://placekitten.com/200/200?image=5", Fotos.Type.VIDEO),           
    Fotos("Title 6", "https://placekitten.com/200/200?image=6", Fotos.Type.PHOTO),           
    Fotos("Title 7", "https://placekitten.com/200/200?image=7", Fotos.Type.PHOTO),           
    Fotos("Title 8", "https://placekitten.com/200/200?image=8", Fotos.Type.PHOTO),           
    Fotos("Title 9", "https://placekitten.com/200/200?image=9", Fotos.Type.VIDEO),           
    Fotos("Title 10", "https://placekitten.com/200/200?image=10", Fotos.Type.PHOTO),         
)                                                                                            
//Forma abreviada                                                                            
fun incluirFoto2(): List = (1..10).map {                                               
    Fotos("Title $it","https://placekitten.com/200/200?image=$it",                           
        if (Random.nextBoolean()) Fotos.Type.VIDEO else Fotos.Type.PHOTO)                    
}
fun main() {
    val listado = listOf("Lestrades","Jose","Paco","Ana")
    println("Toda la lista: $listado")
    println("Orden alfabético: ${listado.sorted()}")
    println("Orden inverso al original: ${listado.reversed()}")
    println("Orden alfabético inverso: ${listado.sorted().reversed()}")
    println("La posición de Jose es: ${listado.indexOf("Jose")}")
}
/*
Salida===>
Toda la lista: [Lestrades, Jose, Paco, Ana]
Orden alfabético: [Ana, Jose, Lestrades, Paco]
Orden inverso al original: [Ana, Paco, Jose, Lestrades]
Orden alfabético inverso: [Paco, Lestrades, Jose, Ana]
La posición de Jose es: 1
*/

  • Clases:

//Los nombres de clases se escriben con la primera letra en mayúscula.
//class Clase (var/val tipo:propiedad, var/val tipo:propiedad = inicializada,...){propiedades y funciones }
class Libro(){
    var titulo = "Lestradamus"
} 

fun main(args: Array) {
    print(Libro())
}

//Salida===> Libro@5451c3a8


//Los nombres de clases se escriben con la primera letra en mayúscula. 
//class Clase (var/val tipo:propiedad, var/val tipo:propiedad = inicializada,...){propiedades y funciones } 
class Libro(var titulo: String){ 
}
fun main(args: Array) {
    var libro = Libro("Lestradamus")
    print(libro)
}
//Salida ===> Libro@5451c3a8

class Libro(var titulo: String){
    
}
fun main(args: Array) {
    var libro = Libro("Lestradamus")
    print(libro.titulo)//Se puede observar que hay que dirigirse a su propiedad para poder imprimirla
}
//Salida===> Lestradamus
class Libro(var numero: Int,var titulo: String){
    constructor(): this(1,"Jose")    
}
fun main(args: Array) {
    var libro = Libro(0,"Lestradamus")
    val libro2 = Libro()
    
    println("${libro.numero} ${libro.titulo}")
    println("${libro2.numero} ${libro2.titulo}")
}
//Salida===> 0 Lestradamus
//           1 Jose
class Libro(var numero: Int,var titulo: String){
    constructor(): this(1,"Jose")
    override fun toString(): String {
        return "Numero: $numero Título: $titulo"
    }    
}
fun main(args: Array) {
    var libro = Libro(1,"Lestradamus") 
    println(libro) //Antes era necesario println("Numero: ${libro.numero} Título: ${libro.titulo}")  
}
//Salida==> Numero: 1 Título: Lestradamus
class Libro(var numero: Int,var titulo: String){
    var iva : Float = 21f
    get()= field/100
    var precio: Float = 0f
    //Cogemos el valor de la entrada
    set(value){
        field = value
    }
    //transformamos al valor de salida
    get() = (field*iva)+field
    fun precioIva(): String = "El libro $titulo cuesta $precio €"    
}
fun main(args: Array) {
    var libro = Libro(1,"Lestradamus")
    libro.precio = 100f
    println(libro.precioIva())
}
//Salida===> El libro Lestradamus cuesta 121.0 €

//Para que se pueda heredar de una clase hay que poner la palabra open delante de la palabra class.

//Para heredar sus funciones también hay que poner la palabra open delante de la palabra fun.

open class Proyectil(var cantidad: Int,var velocidad: Float){ // Caso padre un proyectil normal pueden impactar varios en el objetivo casi a la vez
    constructor(): this(1,10f)
    open fun herida( damage: Float= 10f): Float{ //El daño es de 10 por la cantidad de impactos
        return damage * this.cantidad
    }
}
// El caso de la flecha, solo impacta una a la vez
class Flecha (cantidad: Int = 1,velocidad : Float, damage: Float): Proyectil(cantidad,velocidad){
    override fun herida(damage: Float): Float {
        return damage
    }
}
fun main(args: Array) {
    var bala: Proyectil = Proyectil(cantidad = 3,velocidad = 250f)
    var flecha : Flecha = Flecha(velocidad = 100f,damage =15f)//La cantidad la hemos metido de serie en la clase
    println("El damage de la bala es: ${bala.herida()}")
    println("El damage de la flecha es: ${flecha.herida()}")
}
/* Salida===>El damage de la bala es: 30.0
             El damage de la flecha es: 10.0
*/
  • Super: Hace referencia a la clase padre.
  • field: Variable especial dentro de los métodos get y set:
    • // Estas dos clases son la misma
      // Kotlin nos ahorra tiempo a la hora de definir los Getters y Setters
      class animal{
          var peso = 100
      }
      class animal2{
          var peso = 100
              get()= field
              set(valor){
                  field = valor
              }
      }

Los modificadores de visibilidad en Kotlin, con el fin de restringir el uso de clases, objetos, interfaces, constructores, funciones, propiedades y sus setters:

  • private: Marca una declaración como visible en la clase o archivo actual.
  • protected: Marca una declaración como visible en la clase y subclases de la misma.
  • internal: Marca una declaración como visible en el módulo actual.
  • public: Marca una declaración como visible en todas partes.

Packages
Las funciones,propiedades y clases,objetos e interfaces pueden ser declarados en el «nivel superior»,es decir,directamente dentro de un paquete:

  • Si no especifica ningún modificador de visibilidad, public se usa por defecto, lo que significa que sus declaraciones serán visibles en todas partes.
  • Si marca una declaración como private , solo será visible dentro del archivo que contiene la declaración.
  • Si lo marca como internal , es visible en todas partes del mismo módulo.
  • protected no está disponible para declaraciones de nivel superior.

Clases e Interfaces
Para los miembros declarados dentro de una clase:

  • open: para poder crear hijos de esta clase, no es un nivel de visibilidad pero viene bien tenerlo a mano por aquí
  • private:  significa visible solo dentro de esta clase (incluidos todos sus miembros).
  • protected :  igual que private  y además visible también en subclases.
  • internal : cualquier cliente dentro de este módulo que ve la clase declarante ve sus miembros internal .
  • public : cualquier cliente que vea la clase declarante ve a sus miembros public.

Hay que tener en cuenta que en Kotlin, la clase externa no ve los miembros privados de sus clases internas.

Si anulas un miembro protected y no especificas la visibilidad explícitamente, el miembro anulado también tendrá visibilidad protected .

open class A {
    public var m1 = 10
    internal var m2 = "Propiedad interna"

    private fun m3() = println("Método privado")

    protected open fun m4() = m1 + 10
}


class B : A() {
    // m1 es visible pero no se puede sobrescribir

    // m2 es visible pero no se puede sobrescribir

    // m3 no es visible

    // m4 es visible y se puede sobrescribir
    public override fun m4() = m1 + 100
}

Se utiliza para declarar una propiedad estática, que puede estar disponible para el resto del proyecto, como por ejemplo una variable global.

class Proyectil(var cantidad: Int,var velocidad: Float){
    constructor(): this(1,10f)
    fun herida( damage: Float= 10f): Float{
        return damage * this.cantidad
    }
    companion object{
        const val armaActiva = true
        const val armaInactiva = false
    }
}
fun main(args: Array) {
    var bala: Proyectil = Proyectil(cantidad = 3, velocidad=250f)
    println("El damage de la bala es: ${bala.herida()}")
    println ("El arma esta activa: ${Proyectil.armaActiva}")
}
/* Salida===> El damage de la bala es: 30.0
              El arma esta activa: true
*/

Se utiliza para crear listas que van a ser siempre las mismas, como por ejemplo los días de la semana, o los planetas del sistema solar.

enum class Proyectil(var tipo: String) {
    FUEGO("Arma de fuego"),
    LARGO_ALCANCE("Largo alcance, arcos, ballestas,jabalinas.")
}
fun main(args: Array) {
    println("El proyectil  es: ${Proyectil.FUEGO}")
    println("El proyectil  es: ${Proyectil.LARGO_ALCANCE.tipo}")

}
/* Salida===> El proyectil  es: FUEGO
              El proyectil  es: Largo alcance, arcos, ballestas,jabalinas.
*/

Simplemente son clases dentro de clases:

class Proyectil(var tipo: String) {
    enum class Tipos(var tipo:String){
        FUEGO("Arma de fuego"),
        LARGO_ALCANCE("Largo alcance, arcos, ballestas,jabalinas.")
    }
}
fun main(args: Array) {
    val pistola: Proyectil= Proyectil(Proyectil.Tipos.FUEGO.tipo)
    println("El proyectil  es: ${pistola.tipo}")
}
/* Salida===> El proyectil  es: Arma de fuego
*/

Con la inner class se puede acceder a las propiedades de su clase externa, en el siguiente ejemplo se puede ver como se accede a una propiedad privada de la clase padre.

class Proyectil() {
    private var tipos = "Armas de fuego"
    inner class Tipos(){
        fun tipo()= tipos
    }
}
fun main(args: Array) {
    val pistola = Proyectil().Tipos().tipo()
    println("El proyectil  es: ${pistola}")
}
/* Salida===> El proyectil  es: Armas de fuego
*/

La interfaz es una especie de plantilla que podemos implementar en otras clases.

interface Vehiculo{
    fun ruedas():Int
    fun peso():Int
    fun puertas():Int
}
class Coche(var nombre:String) : Vehiculo{
    override fun ruedas(): Int = 4
    override fun peso(): Int = 1200
    //Otro modo de hacerlo
    override fun puertas(): Int {
        return 4
    }
    override fun toString(): String {
        return nombre
    }
}
fun main(args: Array) {
    val seatPanda : Coche = Coche("Seat Panda")
    println("Vehiculo: ${seatPanda}")
    println("Ruedas: ${seatPanda.ruedas()}")
    println("Peso: ${seatPanda.peso()}")
    println("Puertas: ${seatPanda.puertas()}")
}
/*Salida===> Vehiculo: Seat Panda
                       Ruedas: 4
                       Peso: 1200
                       Puertas: 4
*/

Con este modificador facilitamos la creación de clases cuyo propósito es el almacenamiento de valores, se utiliza mucho para cuando se crea una base de datos. Al crear esta clase se generan unos atributos que ayudan con el tratamiento de datos:

  • equals: Compara el contenido significativo de los objetos. Es decir, dos objetos serán iguales si los valores de sus propiedades son iguales.
  • hasCode:
  • copy: Para copiar un elemento
  • componentN:  corresponden a cada propiedad en orden de declaración.
data class Coche(var nombre:String,var ruedas: Int,var peso:Int){   
}
fun main(args: Array) {
    val seatPanda = Coche("Seat Panda", 4, 1200)
    val fordFocus = Coche("Ford Focus",5,1350)
    println(seatPanda) //Diferencia a la hora de imprimirlo sin toString
    //Se pueden comparar valores gracias a equals ==
    println("Son iguales los coches: ${seatPanda == fordFocus}")
    println("Son iguales los coches: ${seatPanda.equals(fordFocus)}")
    //Se pueden copiar los valores de un objeto en otro
    var fordFocus2 = fordFocus.copy()
    println(fordFocus2)
    //Se puede acceder a cualquiera de sus valores
    println("Ruedas: ${fordFocus.ruedas}")
    println("Peso: ${fordFocus.component3()}")
}
/* Salida===>Coche(nombre=Seat Panda, ruedas=4, peso=1200)
             Son iguales los coches: false
             Son iguales los coches: false
             Coche(nombre=Ford Focus, ruedas=5, peso=1350)
             Ruedas: 5
             Peso: 1350
*/

La palabra infix hace que se pueda crear una función que sea una extensión de una clase.

Requerimientos Al Crear Una Función infix
Para que la notación infix sea satisfecha debes cumplir las siguientes restricciones en la declaración de la función:

  • Debe ser una función miembro o función de extensión.
  • Debe recibir un solo parámetro. Este será el operando de mano derecha de la expresión.
  • El parámetro no debe aceptar argumentos variables ni tener un valor por defecto.

En este caso se ha creado un algoritmo que precisa un texto y lo convierte en un salteado de mayúsculas y minúsculas:

fun main() {
    val texto = "Lestradamus"
    println(texto.convertir(true))
    println(texto.convertir(false))
}
private infix fun String.convertir(empMayus: Boolean): String {
    var convertido = ""
    var indice = 0
    var modulo = 0
    if (empMayus) {
        this.uppercase()
    } else {
        this.lowercase()
        modulo = 1
    }
    while (indice < this.length) { if (indice % 2 == modulo) { convertido += this.get(indice).uppercase() } else { convertido += this.get(indice).lowercase() } indice++ } return convertido } /* Salida===>LeStRaDaMuS
             lEsTrAdAmUs
 */

  • Plugins:

Plugin para poner color a las tabulaciones:

Plugin para poner color a los corchetes y paréntesis:

Simplemente convierte un JSON a una clase de Kotlin.

  • Librerías:

implementation 'com.github.bumptech.glide:glide:4.13.2'

  • Trucos:

En el menú de arriba en Edit seleccionamos Column Selection Mode con un carácter del código seleccionado.

Y con la tecla mayúsculas apretada movemos el cursor hacia abajo tantas veces como filas queramos poner la misma expresión.

Los typealias o los alias de tipo, se usan para dar nombres alternativos a unos tipos existentes.

private typealias Popins = Supercalifragilisticoespialidoso
fun main(){
    Supercalifragilisticoespialidoso().saluda("Hola")
    val saluda = Popins().saluda("Hola2")
    
}
class Supercalifragilisticoespialidoso (){
    fun saluda(value: String){
        println(value)
    }
}
// Salida ==>   Hola
//              Hola2