owned this note
owned this note
Published
Linked with GitHub
---
title: Kotlin sacándole los colores a Java
tags: Kotlin, Java
description: Presentación sobre Kotlin en comparación con Java
slideOptions:
theme: beige
transition: 'slide'
mouseWheel: true
touch: true
controlsLayout: 'edges'
hideAddressBar: true
keyboard: true
overview: false
---
# Kotlin
## Sacándole los colores a Java
Pedro Joya Máñez

https://hackmd.io/@pedrojoya/kotlin#/
---
### Acerca de mí
#### Pedro Joya
:man:
- Docente de Ciclos Formativos de Formación Profesional de Informática en el IES Saladillo de Algeciras
- Profesor de desarrollo de aplicaciones en Android
- Apasionado de Kotlin
twitter: [@pedrojoyamanez](https://twitter.com/pedrojoyamanez)
---
### ¿Qué es Kotlin?
- Lenguaje de programación creado por JetBrains
- Inspirado en otros lenguajes: Java, C#, Scala, Groovy, Ruby
- Podemos usarlo para desarrollo mobile, web front-end y back-end (Spring, Android, web, nativo)
---
### ¿Por qué Kotlin?
- Sintaxis simple y concisa
- Curva de aprendizaje suave
- Interoperable con Java. Compila hacia JVM bytecode
- Lenguaje moderno, conciso y con características de lenguajes funcionales
- Google lo ha elegido como lenguaje prioritario para programación en Android
---

---
### Show me the code

---
### El ; es opcional
```java=
// JAVA
String name = "Baldomero";
```
```kotlin=
// KOTLIN
val name: String = "Baldomero"
```
* En Kotlin el ; es opcional, excepto en un caso específico de los enums :scream: :clap: :dancer:
---
### val vs. var
```java=
// JAVA
final String name = "Baldomero";
int age = 45;
```
```kotlin=
// KOTLIN
val name: String = "Baldomero"
var age: Int = 45
```
- val define una variable que no puede referenciar ningún otro objeto en el futuro.
- var define una varible que puede referenciar distintos objetos a lo largo de su vida
---
### Inferencia de tipos
```java=
// JAVA <10
final String name = "Baldomero";
// JAVA 10
var name = "Baldomero";
```
```kotlin=
// KOTLIN
var name = "Baldomero"
```
- Tipo inferido (deducido) a partir del tipo de la expresión de inicialización
- Lenguaje fuertemente tipado de tipo estático, aunque haya sido inferido (tiempo de compilación)
---
### Tipos referenciales, no primitivos
```kotlin=
// KOTLIN
val value: Int = 146
val percent = value.coerceIn(0, 100)
```
- No exiten los tipos primitivos, todos son clases.
- Internamente se usará un tipo primitivo cuando sea posible, con boxing y unboxing automático
- No hay conversión automática de tipos numéricos, sino funciones de conversión explícita en los tipos, como toLong(), toInt(), etc.
---
### Template Strings (interpolación)
```java=
// JAVA
final String s = "abc";
System.out.println(s + ".length is " + s.length());
```
```kotlin=
// KOTLIN
val s = "abc"
println("$s.length is ${s.length}")
```
- $variable para interpolar el valor de una variable
- ${expresion} para interpolar el valor de cualquier expresión
---
### Raw Strings
```java=
// JAVA
final String artist = "Chiquito de la Calzada";
final String saying = "No te digo trigo...\n" +
"por no llamarte Rodrigo\n" +
"(" + artist + ")";
```
```kotlin=
// KOTLIN
val artist = "Chiquito de la Calzada"
val saying = """
|No te digo trigo
|por no llamarte Rodrigo
|($artist)
""".trimMargin()
```
- Literal de cadena sin caracteres de escape (\n, \t, ...)
- Puede contener interpolación.
- Se propuso para Java 12, pero fue pospuesto.
---
### if else es una expresión
```kotlin=
// KOTLIN
val max = if (a > b) {
print("a es el máximo")
a
} else {
print("b es el máximo")
b
}
```
- Las estructura if else es una expresión, que se evalúa al valor al que se evalúa la rama ejecutada
- Una rama se evalúa al valor al que se evalúa la última expresión de la rama
---
### No hay operador ternario
```java=
// JAVA
final int max = a > b ? a : b;
```
```kotlin=
// KOTLIN
val max = if (a > b) a else b
```
- En este caso Kotlin puede resultar más verboso que Java :confused:
---
### Estructura for
```java=
// JAVA
for (int i = 1; i <= 10; i++)
System.out.println(i);
```
```kotlin=
// KOTLIN
for (i in 1..10)
println(i)
```
- Kotlin no posee la estructura for tradicional de Java
- Sólo for sobre iterador (for each)
- Podemos usar un literal de rango de valores para iterar sobre él
---
### Range
```java=
// JAVA
for (int i = 1; i < 10; i++)
System.out.println(i);
for (int i = 6; i >= 0; i-=2)
System.out.println(i);
```
```kotlin=
// KOTLIN
for (i in 1 until 10)
println(i)
for (i in 6 downTo 0 step 2)
println(i)
```
- La clase Range modela un rango de datos y posee un iterador
- Podemos usar los métodos until, downTo y step para crear el rango adecuado
---
### when como switch mejorado
```kotlin=
when (input) {
1 -> println("Uno")
7, 8 -> println("Siete u ocho")
in 10..19 -> println("Decena")
is String -> println("Cadena de ${input.length}")
else -> {
println("Otra cosa")
println("Lo sentimos")
}
}
```
- No necesita break
- Más de un valor de comparación en cada rama
- Comprobación de pertenencia o no a un rango, array o lista
- Comprobación de pertenencia o no a un tipo
---
### when es una expresión
```kotlin=
val semester = when (month) {
in 1..6 -> "Primer semestre"
in 7..12 -> "segundo semestre"
else -> "Mes no válido"
}
```
- Devuelve el valor al que se evalúa la rama seleccionada, que corresponde al valor al que se evalúa su última expresión
- Debe ser exhaustivo (abarcar todas las posibilidades)
- Java 12 incorpora una versión preliminar de switch mejorado con funcionalidad similar
---
### when como if else if
```java=
// JAVA
if (x.isOdd())
System.out.println("x es impar");
else if (x.isEven())
System.out.println("x es par");
else
System.out.println("x está indecisa");
```
```kotlin=
// KOTLIN
when {
x.isOdd() -> println("x is impar")
x.isEven() -> println("x is par")
else -> println("x está indecisa")
}
```
- Las ramas se consideran expresiones booleanas y se ejecutará la primera que sea verdadera
- También puede usarse como expresión
---
### Hydration break

---
### Definición de funciones
```java=
// JAVA
String greet(String name, String message) {
return message + ", " + name;
}
```
```kotlin=
// KOTLIN
fun greet(name: String, message: String): String {
return "$message, $name"
}
```
* fun is :smile:
* El tipo de retorno se coloca al final, pero puede ser inferido
---
### Funciones que no retornan "nada"
```java=
// JAVA
void greet(String name, String message) {
System.out.println(message + ", " + name);
}
```
```kotlin=
// KOTLIN
fun greet(name: String, message: String) {
println("$message, $name")
}
```
- El tipo de retorno es Unit, pero podemos omitirlo
- Unit es un tipo, no una palabra reserva como void
- La función retorna en realidad el objeto Unit (singleton)
---
### Funciones con una única expresión
```java=
// JAVA
String greet(String name, String message) {
return message + ", " + name;
}
```
```kotlin=
// KOTLIN
fun greet(name: String, message: String) = "$message, $name"
```
- El tipo de retorno es inferido a partir del tipo de la expresión, aunque puede ser especificado explícitamente
---
### Argumentos con valores por defecto
```java=
// JAVA
String greet(String name) {
return greet(name, "Hola");
}
String greet(String name, String message) {
return message + ", " + name;
}
```
```kotlin=
// KOTLIN
fun greet(name: String, message: String = "Hola") =
"$message, $name"
```
- Permiten mejorar una API existente fácilmente
- El valor por defecto de un parámetro puede usar el valor de un argumento anterior
- En Java se simulan mediante sobrecarga de métodos
---
### Named arguments
```kotlin=
// KOTLIN
fun greet(name: String = "Baldomero",
message: String = "Hola") = "$message, $name"
println(greet(message="Quillo que"))
println(greet(message="Quillo que", name="Germán Ginés"))
println(greet("Germán Ginés", message="Quillo que"))
```
* Permite especificar sólo algunos argumentos
* Permite cambiar el orden de los argumentos
* Puede usarse en conjunción con el paso de argumentos posicional, empezando por éste
* Esta funcionalidad NO existe en Java
---
### varargs y spread operator
```kotlin=
// KOTLIN
fun printStrings(vararg strings: String) {
for (string in strings)
println(string)
}
val names = arrayOf("Baldomero", "Germán Ginés")
printStrings("Quillo que", *names, "Na aquí")
```
- El operador * (operador de dispersión) delante de un array retorna la lista de valores del array separados por coma ,
---
### Top level functions and properties
```kotlin=
// KOTLIN
// Directamente en un fichero, fuera de cualquier clase
const val PI = 3.14
var isUserLoggedIn: Boolean = false
fun greet(name: String) {
println("Hola $name")
}
fun main() {
greet("Baldomero")
isUserLoggedIn = true
println("El número PI vale $PI")
}
```
- Funciones fuera de cualquier clase. Ejemplo: main
- Propiedades fuera de cualquier clase.
- const para constantes conocidas en tiempo de compilación, que el compilador usará de modo inline
---
### Extension functions
```java=
// JAVA
public static String shout(String receiver) {
return "¡" + receiver.toUpperCase() + "!";
}
String greet = "Quillo que";
System.out.println(StringsUtils.shout(greet));
```
```kotlin=
// KOTLIN
fun String.shout(): String = "¡${this.toUpperCase()}!"
val greet = "Quillo que"
println(greet.shout())
```
- Llamada como si fuera un miembro de una determinada clase.
- El IDE sugiere la función al escribir un . tras una variable de dicho tipo :dancer:
- Dentro de la función, this corresponde al receptor
---
### Lambdas
```kotlin=
// KOTLIN
fun operateAndPrint(x: Int = 0, action: (Int) -> Int): Int {
val result = action(x) // action.invoke(x)
println("Result: $result")
return result
}
val increm3 = { x: Int -> x + 3 }
operateAndPrint(2, increm3)
```
- Tipos función (vs. interf. func. de Java)
- Expresión lambda = literal de objeto función, almacenable y pasable como argumento
- Una lamba se ejecuta mediante el operador () o llamando a su método invoke()
- La expresión lambda se evalúa al valor al que se evalúe la última expresión de su cuerpo
---
### Lambdas como argumento
```kotlin=
// KOTLIN
fun operateAndPrint(x: Int = 0, action: (Int) -> Int): Int {
val result = action(x)
println("Result: $result")
return result
}
operateAndPrint(2, { x -> x + 3})
operateAndPrint(2) { x -> x + 3}
operateAndPrint { x -> x + 3 }
operateAndPrint { it + 3 }
```
- Inferencia de tipos en los parámetros de la lambda
- Si lambda es último argumento, sacar de los ()
- Si lambda es único argumento, nos ahorramos los ()
- Si lambda tiene un solo argumento, usar it en cuerpo
---
### Smart cast
```java=
// JAVA
if (obj instanceof String)
System.out.println(((String) obj).length());
```
```kotlin=
// KOTLIN
if (obj is String)
println(obj.length)
```
- El compilador hace el cast internamente dentro de la rama :bulb:
- Sólo puede aplicarse si la variable no puede cambiar entre la comprobación y el acceso
- También en ramas de la estructura when y en comprobación de no null
---
### Tipos nullable y no nullables
```kotlin=
// KOTLIN
var name: String? = "Baldomero"
var sirname: String = "Llegate Ligero"
name = null
if (name != null)
println(name.length)
```
- Nulabilidad dentro del sistema de tipos.
- Detección de errores relacionados con null en tiempo de compilación :clap:
- Tipo? permite null, Tipo no permite null. Tipo es un subtipo de Tipo?
- Smart cast de Tipo? a Tipo tras comprobación de que la variable no es null
---
### Jerarquía de tipos

- Any es similar a Object
- Cada tipo no nullable es subtipo del correspondiente nullable
- Nothing es subtipo de todos los tipos
---
### Nothing y throw como expresión
```kotlin=
// KOTLIN
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
val fruitPerGlass: Int =
if (glassesSold > 0) orangesUsed / glassesSold
else throw NoGlassesSold()
```
- El tipo Nothing indica que la función nunca terminará satisfactoriamente y por tanto no retornará
- Es subtipo de todos los tipos
- throw es una expresión que retorna Nothing
---
### Operador de acceso seguro
```java=
// JAVA
final Integer length =
nickname != null ? nickname.length() : null;
final String name =
nickname != null ? nickname.toUpperCase() : null;
```
```kotlin=
// KOTLIN
val length: Int? = nickname?.length
val name = nickname?.toUpperCase()
```
- No se permite usar el operador . con variables de tipo nullable (acceso seguro)
- Se debe usar ?. en vez de . para acceder a propiedades y métodos
- Se evalúa a null si la variable contiene null
---
### Operador elvis
```java=
// JAVA
final int length =
nickname != null ? nickname.length() : 0;
```
```kotlin=
// KOTLIN
val length: Int = nickname?.length ?: 0
```
- Devuelve la expresión de la izquierda si ésta es distinta de null y la de la derecha en caso contrario
- Funciona como un valor por defecto si la expresión es null
---
### Operador bang bang
```java=
// JAVA
String name = "Baldomero";
final Integer length = name.length();
```
```kotlin=
// KOTLIN
var name: String? = "Baldomero"
val lenght = name!!.length
```
- Produce NullPointerException si la variable es null
- Se recomienda sólo usarlo cuando estemos completamente seguros de que no es null.
---
### let
```java=
// JAVA
final String name = "Baldomero";
if (name != null) {
System.out.println("Name: " + name);
}
```
```kotlin=
// KOTLIN
val name: String? = "Baldomero"
name?.let {
println("Name: $it")
}
```
- Extension function, sobre cualquier tipo, que recibe como parámetro una expresión lambda
- La lambda es ejecutada pasándole como argumento el objeto sobre el que se ejecuta let
- Retorna el valor retornado por la expresión lambda.
---
### also
```java=
// JAVA
final Student student = new Student();
student.setAge(45);
student.setAddress("c/ Avda. Duque de Rivas, 1")
```
```kotlin=
// KOTLIN
val student: Student = Student().also {
it.age = 45
it.address = "c/ Avda. Duque de Rivas, 1"
}
```
- Similar a let pero retorna el propio objeto sobre el que se ejecuta also
- Se puede usar para configurar un objeto al crearlo antes de retornarlo (patrón builder)
---
### Hydration break

---
### Constructor primario
```java=
// JAVA
final class Student extends Person {
private final boolean isRepeater;
private int age;
public Student(@NotNull String name,
boolean isRepeater, int age) {
super(name);
this.isRepeater = isRepeater;
this.age = age;
}
}
```
```kotlin=
// KOTLIN
class Student(name: String, val isRepeater: Boolean,
var age) : Person(name)
```
- Constructor primario definido en primera linea
- Llamada al constructor primario de la superclase al definir la herencia
---
### Bloque de inicialización
```java=
// JAVA
final class Student extends Person {
private final boolean isRepeater;
private int age;
public Student(@NotNull String name,
boolean isRepeater,
int age) {
super(name);
this.isRepeater = isRepeater;
this.age = age;
// Código de inicialización...
}
}
```
```kotlin=
// KOTLIN
class Student(name: String,
val isRepeater: Boolean,
var age: Int) : Person(name) {
init {
// Código de inicialización...
}
}
```
- Código de inicialización en bloque init.
---
### Instanciación
```java=
// JAVA
final Student student = new Student("Baldomero",
false, 23);
```
```kotlin=
// KOTLIN
val student = Student("Baldomero", false, 23)
```
- No existe el operador new
---
### Concepto de propiedad
```java=
// JAVA
final class Student extends Person {
private final boolean isRepeater;
private int age;
private int grade;
public Student(@NotNull String name,
boolean isRepeater,
int age) {
super(name);
this.isRepeater = isRepeater;
this.age = age;
}
public boolean isRepeater() { return isRepeater; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public int getGrade() { return grade; }
public void setGrade(int grade) { this.grade = grade; }
}
```
- Al conjunto formado por el campo (field), el getter y el setter se le conoce como propiedad
---
### Propiedades en Kotlin
```kotlin=
// KOTLIN
class Student(name: String,
val isRepeater: Boolean,
var age: Int) : Person(name) {
var grade: Int = 0
}
```
- Definidas directamente en el constructor primario o en el cuerpo de la clase
- Los parámetros del constructor sin val ni var NO crean propiedades. Son valores para inicialización de otras propiedades
---
### Getter y setters personalizados
```kotlin=
// KOTLIN
class Student(name: String, val isRepeater: Boolean, var age: Int) : Person(name) {
var grade: Int = 0
set(value) {
if (value >= 0) field = value
else throw IllegalArgumentException()
}
val gradeDescription: String
get() = when(grade) {
in 0..4 -> "Mal"
in 5..7 -> "Aceptable"
in 8..10 -> "Bien"
else -> "No válida"
}
}
```
- field representa el campo interno creado
- Podemos crear propiedades que no tienen ningún campo asociado
---
### Acceso a propiedades
```java=
// JAVA
final Student student =
new Student("Baldomero", false, 25);
System.out.println(student.getName());
student.setGrade(8);
System.out.println(student.getGradeDescription());
```
```kotlin=
// KOTLIN
val student = Student("Baldomero", false, 25)
println(student.name)
student.grade = 8
println(student.gradeDescription)
```
- Se usa el operador . para acceder a una propiedad, tanto para lectura como para escritura.
---
### Notación infix
```java=
// JAVA
public final class Pizza {
public final void add(@NotNull String ingredient) {
System.out.println(ingredient + " added to pizza");
}
}
Pizza pizza = new Pizza();
pizza.add("Cheese");
```
```kotlin=
// KOTLIN
class Pizza {
infix fun add(ingredient: String) {
println("$ingredient added to pizza")
}
}
val pizza = Pizza()
pizza add "Cheese"
```
- Notación de operaciones aritméticas binarias
- Método o extension function con un único parámetro
---
### Concepto de data class
```java=
// JAVA
public final class User {
@NotNull private final String name;
private final int age;
public User(@NotNull String name, int age) { ... }
@NotNull public final String getName() { ... }
public final int getAge() { ... }
@NotNull public String toString() { ... }
public int hashCode() { ... }
public boolean equals(@Nullable Object var1) { ... }
// ...
}
```
- Clase cuyo propósito principal es contener datos. Habitualmente implementan equals(), hashCode() y toString().
---
### Data class en Kotlin
```kotlin=
data class User(val name: String, val age: Int)
```
- Implementaciones por defecto del constructor, getters de propiedades, setters para propiedades var, toString(), hashCode(), equals()
- Se puede implementar explícitamente toString(), hashCode() y equals() en el cuerpo de la clase
- Implementación del método copy() para crear un nuevo objeto a partir de uno existente
- Implementación de métodos para desestructuración: component1(), component2(), etc.
---
### Desestructuración
```java=
User jane = new User("Jane", 35);
String name = jane.component1();
int age = jane.component2();
```
```kotlin=
val jane = User("Jane", 35)
val (name, age) = jane
```
- Asignación a lista de variables individuales, desde propiedades de un objeto (o elementos de colección)
---
### Delegación
```kotlin=
interface Base {
fun print()
}
// Cuando se llame al método print() sobre un objeto de la clase
// Derived se llamará automáticamente al método print() de objeto b.
class Derived(b: Base) : Base by b {
// Otros métodos
}
```
- Delegación y composición vs. herencia
- El compilador generará automáticamente en la clase Derived el método print(), que internamente llamará a b.print()
---
### Object
```java=
public final class RepositoryImp implements Repository {
public static final RepositoryImp INSTANCE =
new RepositoryImp();
private RepositoryImp() { }
// ...
}
RepositoryImp repository = RepositoryImp.INSTANCE;
```
```kotlin=
object RepositoryImp : Repository {
// ...
}
val repository = RepositoryImp.INSTANCE
```
- Patrón singleton en modo eager con solo usar object en vez de class
---
### Sealed classes
```kotlin=
sealed class Post
// Las clases hijas pueden ser clases normales, data classes e incluso objects.
data class Status(var text: String) : Post()
data class Image(var url: String, var caption: String) : Post()
data class Video(var url: String, var timeDuration: Int, var encoding: String): Post()
object Headline : Post()
```
- Clase que sólo puede tener unas determinadas clases hijas predefinidas
- Es abstracta por definición
- Tanto la clase padres como las hijas deben estar definidas en el mismo fichero
---
### No exite la palabra reservada static
```java=
// JAVA
class Person {
public static void callMe() { }
}
Person.callMe();
```
```kotlin=
// KOTLIN
class Person {
companion object {
fun callMe() { }
}
}
Person.callMe()
```
- Clases de utilidad no necesarias (extension functions y top level functions)
- Companion object asociado a una clase
---
### Sobrecarga de operadores
```kotlin=
// KOTLIN
data class Point(var x: Double, var y: Double) {
operator fun plus(point: Point) =
Point(x + point.x, y + point.y)
}
val p1 = Point(2.9, 5.0)
val p2 = Point(2.0, 7.5)
val p3 = p1 + p2
```
- Conjunto predefinido de operadores con representación simbólica; +, - , ...
- Al usar un operador internamente se llama al método asociado a él: a + b se traduce a a.plus(b)
- Podemos definir el método asociado a un determinado operador en nuestras clases
---
### Asociaciones de operadores
| Expresión | Se traduce a |
| ----------- | --------------------------------- |
| a + b, a - b, a * b | a.plus(b), a.minus(b), a.times(b) |
| a..b, a in b | a.rangeTo(b), b.contains(a) |
| a[i], a[i] = b | a.get(i), a.set(i, b) |
| a() | a.invoke() |
| a == b | a?.equals(b) ?: (b === null) |
| a > b | a.compareTo(b) > 0 |
| a += b | a.plusAssign(b) |
---
### Colecciones mutables e inmutables
```kotlin=
// KOTLIN
val inmutableList = listOf(1, 2, 3)
val mutableList = mutableListOf(1, 2, 3)
mutableList.add(4)
```
- Interfaces distintas para colecciones inmutables y mutables
---
### Trabajo funcional con colecciones
```java=
// JAVA 9
List.of(4, -1, 2, -8)
.stream()
.filter(it -> it > 0)
.map(it -> it * 2)
.forEach(System.out::println);
```
```kotlin=
// KOTLIN
listOf(4, -1, 2, -8)
.filter { it > 0 }
.map { it * 2 }
.forEach(::println)
```
- Métodos de filtrado, transformación, reducción, etc. directamente en las colecciones
- Por defecto eager aunque puede convertirse en lazy
- lambdas y referencias a métodos
---
### Otros cambios
- Las clases y los métodos son públicos por defecto
- Las clases y los métodos son final por defecto (usar open para abrirlos)
- Las clases internas son static por defecto
- protected es más restrictivo: sólo subclases
- Modificador de acceso internal para visibilidad a nivel de módulo
- Un fichero puede tener más de una clase pública
- No existen las checked exceptions. Tampoco throws
---
## En resumen...
---

---
### Referencias
- Web oficial: [https://kotlinlang.org/](https://kotlinlang.org/)
- Playground: [https://play.kotlinlang.org](https://play.kotlinlang.org)
- Learn Kotlin: [https://kotlinlang.org/docs/reference/](https://kotlinlang.org/docs/reference/)
---
