Hello World y conceptos básicos
Un programa Kotlin empieza en una función main de nivel superior: no hace falta una clase.
| Sintaxis | Significado |
|---|
fun main() { println("Hello") } | Punto de entrada de un programa |
println("text") | Imprimir una línea en la salida estándar |
print("text") | Imprimir sin salto de línea al final |
// comment | Comentario de una línea |
/* comment */ | Comentario de varias líneas |
val input = readLine() | Leer una línea de stdin (String? nullable) |
val line = readln() | Leer una línea de stdin (no nulo, Kotlin 1.6+) |
Variables (val / var) y tipos
Prefiere val; usa var solo cuando el valor tenga que cambiar.
| Sintaxis | Significado |
|---|
val name = "Ada" | Variable de solo lectura, tipo inferido como String |
var count = 0 | Variable mutable |
val age: Int = 30 | Anotación de tipo explícita |
Int, Long, Double, Float | Tipos numéricos (42, 42L, 3.14, 3.14f) |
Boolean, Char, String | true/false, 'a', "texto" |
val big = 1_000_000 | Guiones bajos para literales legibles |
"3".toInt(), "2.5".toDouble() | Convertir un string en número |
42.toString() | Número a string |
const val MAX = 10 | Constante en tiempo de compilación (nivel superior o en un object) |
Strings y plantillas
Las plantillas de string sustituyen a la concatenación casi siempre.
| Sintaxis | Significado |
|---|
"Hi, $name" | Insertar una variable en un string |
"Total: ${price * qty}" | Insertar una expresión |
s.length | Número de caracteres |
s.uppercase(), s.lowercase() | Cambiar mayúsculas/minúsculas |
s.trim() | Quitar espacios al principio y al final |
s.contains("x"), s.startsWith("a") | Buscar dentro de un string |
s.substring(0, 3) | Cortar por rango de índices |
s.split(",") | Dividir en una List<String> |
s[0] | Carácter en un índice |
"""raw text""" | String crudo de varias líneas, sin escapes |
"%.2f".format(3.14159) | Salida formateada (3.14) |
Null safety
Un tipo no admite nulos por defecto; añade ? para permitir null y el compilador te obliga a tratarlo.
| Sintaxis | Significado |
|---|
var s: String? = null | Tipo nullable |
s?.length | Llamada segura: devuelve null si s es null |
s?.length ?: 0 | Operador Elvis: valor por defecto cuando es null |
s!!.length | Aserción de no nulo: lanza excepción si s es null |
if (s != null) s.length | Smart cast a no nulo dentro de la comprobación |
s?.let { println(it) } | Ejecutar un bloque solo cuando no es null |
val n = s?.toIntOrNull() | Convertir, o null si la entrada no es válida |
lateinit var x: String | Variable no nula inicializada más tarde |
Operadores
| Operador | Significado |
|---|
+ - * / % | Aritmética (/ entre Int es división entera) |
+= -= *= /= %= | Asignación compuesta |
++ -- | Incremento / decremento |
== != | Igualdad estructural (llama a equals) |
=== !== | Igualdad referencial (mismo objeto) |
< > <= >= | Comparación |
&& || ! | Y / o / no lógicos |
a in 1..10 | Pertenencia a un rango o colección |
x as Int, x as? Int | Cast / cast seguro (null si falla) |
x is String | Comprobación de tipo (smart cast si acierta) |
Control de flujo (if / when)
if y when son expresiones: devuelven un valor.
| Sintaxis | Significado |
|---|
if (a > b) x else y | if como expresión (Kotlin no tiene ternario ?:) |
if (c) { ... } else if (d) { ... } else { ... } | Ramas encadenadas |
when (x) { 1 -> "one"; 2 -> "two"; else -> "other" } | Comparar con un valor |
when (x) { 1, 2 -> "low" } | Varios valores en una rama |
when (x) { in 1..9 -> "digit" } | Comparar con un rango |
when (x) { is String -> x.length } | Comparar con un tipo (con smart cast) |
when { x < 0 -> "neg"; x == 0 -> "zero"; else -> "pos" } | when sin sujeto, como if/else if |
val label = when (x) { ... } | when como expresión (necesita else) |
Bucles y rangos
| Sintaxis | Significado |
|---|
for (i in 1..5) | Rango inclusivo de 1 a 5 |
for (i in 1 until 5) | De 1 a 4 (fin exclusivo) |
for (i in 0..<5) | Lo mismo con la sintaxis de rango abierto (Kotlin 1.9+) |
for (i in 10 downTo 1 step 2) | Contar hacia atrás por pasos |
for (item in list) | Recorrer una colección |
for ((i, item) in list.withIndex()) | Índice y elemento a la vez |
for (ch in "abc") | Recorrer los caracteres de un string |
while (cond) { ... } | Repetir mientras sea verdadero |
do { ... } while (cond) | Ejecutar al menos una vez |
break, continue | Salir del bucle / saltar a la siguiente iteración |
repeat(3) { println(it) } | Ejecutar un bloque n veces |
Funciones
| Sintaxis | Significado |
|---|
fun add(a: Int, b: Int): Int { return a + b } | Declarar una función |
fun add(a: Int, b: Int) = a + b | Función de una sola expresión, tipo de retorno inferido |
fun greet(name: String = "world") | Valor por defecto de un parámetro |
greet(name = "Ada") | Argumento con nombre |
fun log(vararg items: String) | Número variable de argumentos |
fun say(): Unit | Sin valor de retorno (Unit es opcional) |
val square = { x: Int -> x * x } | Lambda guardada en una variable |
fun String.shout() = uppercase() + "!" | Función de extensión |
fun apply(f: (Int) -> Int) = f(2) | Función como parámetro |
list.map { it * 2 } | Lambda final, it es el único parámetro |
Listas
listOf es de solo lectura; mutableListOf se puede modificar.
| Sintaxis | Significado |
|---|
val nums = listOf(1, 2, 3) | Lista de solo lectura |
val items = mutableListOf("a") | Lista mutable |
nums[0], nums.first(), nums.last() | Acceder a elementos |
nums.getOrNull(9) | Acceso seguro, null si está fuera de rango |
items.add("b"), items.remove("a") | Añadir / eliminar |
items[0] = "z" | Reemplazar por índice |
nums.size, nums.isEmpty() | Tamaño y si está vacía |
x in nums, nums.contains(x) | Pertenencia |
nums.indexOf(2) | Posición de un elemento, -1 si no está |
nums.subList(0, 2) | Sublista (fin exclusivo) |
nums.take(2), nums.drop(1) | Los primeros n / todos menos los primeros n |
nums.sorted(), nums.reversed() | Nueva lista ordenada / invertida |
nums.sum(), nums.average(), nums.maxOrNull() | Agregados |
nums.joinToString(", ") | Unir en un solo string |
Pair(1, "a"), 1 to "a", Triple(1, 2, 3) | Tuplas pequeñas de tamaño fijo |
Mapas y sets
| Sintaxis | Significado |
|---|
val m = mapOf("a" to 1, "b" to 2) | Mapa de solo lectura |
val mm = mutableMapOf<String, Int>() | Mapa mutable |
m["a"] | Búsqueda (null si no existe) |
m.getOrDefault("z", 0) | Búsqueda con valor por defecto |
mm["c"] = 3 | Insertar o actualizar |
for ((k, v) in m) | Recorrer entradas con desestructuración |
m.keys, m.values | Colecciones de claves / valores |
"a" in m | Pertenencia de una clave |
val s = setOf(1, 2, 2) | Set de valores únicos ({1, 2}) |
mutableSetOf<Int>() | Set mutable |
Operaciones sobre colecciones (lambdas)
| Sintaxis | Significado |
|---|
list.map { it * 2 } | Transformar cada elemento |
list.filter { it > 2 } | Conservar los elementos que cumplen la condición |
list.forEach { println(it) } | Hacer algo con cada elemento |
list.any { it > 2 }, list.all { it > 0 } | ¿Algún / todo elemento cumple la condición? |
list.count { it % 2 == 0 } | Contar coincidencias |
list.find { it > 2 } | Primera coincidencia o null |
list.sortedBy { it.length } | Ordenar por una clave |
list.groupBy { it.first() } | Agrupar en un Map |
list.distinct() | Eliminar duplicados |
list.fold(0) { acc, x -> acc + x } | Reducir con un valor inicial |
list.zip(other) | Emparejar dos listas |
list.flatMap { it.toList() } | Transformar y luego aplanar |
Clases y data classes
| Sintaxis | Significado |
|---|
class User(val name: String, var age: Int) | Clase con constructor primario y propiedades |
val u = User("Ada", 36) | Crear una instancia (sin new) |
u.name, u.age = 37 | Leer / escribir propiedades |
data class Point(val x: Int, val y: Int) | equals, hashCode, toString, copy gratis |
p.copy(y = 5) | Copia con algunas propiedades cambiadas |
val (x, y) = p | Declaración de desestructuración |
open class Base, class Sub : Base() | Herencia (las clases son final por defecto) |
override fun toString() = "..." | Sobrescribir un miembro |
object Config { val debug = true } | Singleton |
companion object { fun create() = User("", 0) } | Miembros de tipo estático |
enum class Color { RED, GREEN } | Enum |
sealed class Result | Jerarquía de clases restringida, exhaustiva en when |
interface Shape { fun area(): Double } | Interfaz |
Manejo de errores
| Sintaxis | Significado |
|---|
try { ... } catch (e: Exception) { ... } | Capturar una excepción |
try { ... } finally { ... } | Ejecutar siempre la limpieza |
val n = try { s.toInt() } catch (e: NumberFormatException) { 0 } | try como expresión |
throw IllegalArgumentException("bad") | Lanzar una excepción |
require(x > 0) { "x must be positive" } | Comprobación de argumento (lanza IllegalArgumentException) |
check(ready) { "not ready" } | Comprobación de estado (lanza IllegalStateException) |
s.toIntOrNull() | Devolver null en lugar de lanzar |
runCatching { risky() }.getOrDefault(0) | Envolver una llamada en un Result |
Funciones de ámbito
Cinco pequeñas ayudas para trabajar con un objeto dentro de un bloque.
| Sintaxis | Significado |
|---|
x.let { it + 1 } | it es el objeto, devuelve el resultado del bloque |
x.run { this + 1 } | this es el objeto, devuelve el resultado del bloque |
x.apply { field = 1 } | this es el objeto, devuelve el objeto |
x.also { println(it) } | it es el objeto, devuelve el objeto |
with(x) { field } | No es una extensión; this es x, devuelve el resultado del bloque |
x?.let { ... } | La comprobación de nulo idiomática + uso |
Toda la sintaxis de Kotlin que buscas, en una sola página. Este cheat sheet de Kotlin es una referencia rápida del lenguaje detrás de Android y de buena parte de la JVM moderna: declarar variables, manejar nulos con seguridad, ramificar con when, recorrer rangos, escribir funciones y trabajar con listas y mapas.
Todo lo que hay aquí es Kotlin estándar y funciona igual en la JVM, en Android y con Kotlin Multiplatform. Copia lo que necesites o pruébalo en vivo en el playground de Kotlin: pega un fragmento, pulsa Run y mira la salida en tu navegador.