Hello World e basi
Un programma Kotlin parte da una funzione main di primo livello, senza bisogno di una classe.
| Sintassi | Significato |
|---|
fun main() { println("Hello") } | Punto di ingresso del programma |
println("text") | Stampare una riga sullo standard output |
print("text") | Stampare senza andare a capo |
// comment | Commento su una riga |
/* comment */ | Commento su più righe |
val input = readLine() | Leggere una riga da stdin (String? nullable) |
val line = readln() | Leggere una riga da stdin (non null, Kotlin 1.6+) |
Variabili (val / var) e tipi
Preferisci val; usa var solo quando il valore deve cambiare.
| Sintassi | Significato |
|---|
val name = "Ada" | Variabile di sola lettura, tipo dedotto come String |
var count = 0 | Variabile modificabile |
val age: Int = 30 | Annotazione di tipo esplicita |
Int, Long, Double, Float | Tipi numerici (42, 42L, 3.14, 3.14f) |
Boolean, Char, String | true/false, 'a', "text" |
val big = 1_000_000 | Underscore per letterali più leggibili |
"3".toInt(), "2.5".toDouble() | Convertire una stringa in numero |
42.toString() | Da numero a stringa |
const val MAX = 10 | Costante a tempo di compilazione (a livello top o in un object) |
Stringhe e template
Gli string template sostituiscono la concatenazione quasi ovunque.
| Sintassi | Significato |
|---|
"Hi, $name" | Inserire una variabile in una stringa |
"Total: ${price * qty}" | Inserire un'espressione |
s.length | Numero di caratteri |
s.uppercase(), s.lowercase() | Cambiare maiuscole e minuscole |
s.trim() | Rimuovere gli spazi iniziali e finali |
s.contains("x"), s.startsWith("a") | Cercare dentro una stringa |
s.substring(0, 3) | Porzione per intervallo di indici |
s.split(",") | Dividere in una List<String> |
s[0] | Carattere a un indice |
"""raw text""" | Stringa grezza su più righe, senza escape |
"%.2f".format(3.14159) | Output formattato (3.14) |
Null safety
Un tipo è non null per impostazione predefinita; aggiungi ? per permettere null e il compilatore ti obbliga a gestirlo.
| Sintassi | Significato |
|---|
var s: String? = null | Tipo nullable |
s?.length | Safe call: restituisce null se s è null |
s?.length ?: 0 | Operatore Elvis: valore di riserva quando è null |
s!!.length | Asserzione not-null: lancia un'eccezione se s è null |
if (s != null) s.length | Smart cast a non null dentro il controllo |
s?.let { println(it) } | Eseguire un blocco solo se non è null |
val n = s?.toIntOrNull() | Convertire, oppure null se l'input non è valido |
lateinit var x: String | Var non null inizializzata in seguito |
Operatori
| Operatore | Significato |
|---|
+ - * / % | Aritmetici (/ tra Int è divisione intera) |
+= -= *= /= %= | Assegnazione composta |
++ -- | Incremento / decremento |
== != | Uguaglianza strutturale (chiama equals) |
=== !== | Uguaglianza referenziale (stesso oggetto) |
< > <= >= | Confronto |
&& || ! | And / or / not logici |
a in 1..10 | Appartenenza a un range o a una collezione |
x as Int, x as? Int | Cast / cast sicuro (null se fallisce) |
x is String | Controllo di tipo (smart cast se riesce) |
Controllo del flusso (if / when)
if e when sono espressioni: restituiscono un valore.
| Sintassi | Significato |
|---|
if (a > b) x else y | if come espressione (Kotlin non ha il ternario ?:) |
if (c) { ... } else if (d) { ... } else { ... } | Rami concatenati |
when (x) { 1 -> "one"; 2 -> "two"; else -> "other" } | Confrontare un valore |
when (x) { 1, 2 -> "low" } | Più valori in un solo ramo |
when (x) { in 1..9 -> "digit" } | Confrontare con un range |
when (x) { is String -> x.length } | Confrontare il tipo (con smart cast) |
when { x < 0 -> "neg"; x == 0 -> "zero"; else -> "pos" } | when senza soggetto, come if/else if |
val label = when (x) { ... } | when come espressione (serve else) |
Cicli e range
| Sintassi | Significato |
|---|
for (i in 1..5) | Range inclusivo da 1 a 5 |
for (i in 1 until 5) | Da 1 a 4 (fine esclusa) |
for (i in 0..<5) | Uguale, con la sintassi del range aperto (Kotlin 1.9+) |
for (i in 10 downTo 1 step 2) | Conto alla rovescia a passi |
for (item in list) | Iterare una collezione |
for ((i, item) in list.withIndex()) | Indice ed elemento insieme |
for (ch in "abc") | Iterare i caratteri di una stringa |
while (cond) { ... } | Ciclare finché è vero |
do { ... } while (cond) | Eseguire almeno una volta |
break, continue | Uscire dal ciclo / passare all'iterazione successiva |
repeat(3) { println(it) } | Eseguire un blocco n volte |
Funzioni
| Sintassi | Significato |
|---|
fun add(a: Int, b: Int): Int { return a + b } | Dichiarare una funzione |
fun add(a: Int, b: Int) = a + b | Funzione a espressione singola, tipo di ritorno dedotto |
fun greet(name: String = "world") | Valore predefinito di un parametro |
greet(name = "Ada") | Argomento con nome |
fun log(vararg items: String) | Numero variabile di argomenti |
fun say(): Unit | Nessun valore di ritorno (Unit è opzionale) |
val square = { x: Int -> x * x } | Lambda salvata in una variabile |
fun String.shout() = uppercase() + "!" | Funzione di estensione |
fun apply(f: (Int) -> Int) = f(2) | Funzione come parametro |
list.map { it * 2 } | Trailing lambda, it è l'unico parametro |
Liste
listOf è di sola lettura; mutableListOf si può modificare.
| Sintassi | Significato |
|---|
val nums = listOf(1, 2, 3) | Lista di sola lettura |
val items = mutableListOf("a") | Lista modificabile |
nums[0], nums.first(), nums.last() | Accedere agli elementi |
nums.getOrNull(9) | Accesso sicuro, null se fuori intervallo |
items.add("b"), items.remove("a") | Aggiungere / rimuovere |
items[0] = "z" | Sostituire per indice |
nums.size, nums.isEmpty() | Dimensione e verifica se è vuota |
x in nums, nums.contains(x) | Appartenenza |
nums.indexOf(2) | Posizione di un elemento, -1 se assente |
nums.subList(0, 2) | Porzione (fine esclusa) |
nums.take(2), nums.drop(1) | Primi n / tutti tranne i primi n |
nums.sorted(), nums.reversed() | Nuova lista ordinata / invertita |
nums.sum(), nums.average(), nums.maxOrNull() | Aggregati |
nums.joinToString(", ") | Unire in un'unica stringa |
Pair(1, "a"), 1 to "a", Triple(1, 2, 3) | Piccole tuple fisse |
Map e set
| Sintassi | Significato |
|---|
val m = mapOf("a" to 1, "b" to 2) | Map di sola lettura |
val mm = mutableMapOf<String, Int>() | Map modificabile |
m["a"] | Ricerca (null se manca) |
m.getOrDefault("z", 0) | Ricerca con valore di riserva |
mm["c"] = 3 | Inserire o aggiornare |
for ((k, v) in m) | Iterare le voci con il destructuring |
m.keys, m.values | Collezioni di chiavi / valori |
"a" in m | Presenza di una chiave |
val s = setOf(1, 2, 2) | Set di valori unici ({1, 2}) |
mutableSetOf<Int>() | Set modificabile |
Operazioni sulle collezioni (lambda)
| Sintassi | Significato |
|---|
list.map { it * 2 } | Trasformare ogni elemento |
list.filter { it > 2 } | Tenere gli elementi che corrispondono |
list.forEach { println(it) } | Fare qualcosa con ciascuno |
list.any { it > 2 }, list.all { it > 0 } | Qualche / ogni elemento corrisponde |
list.count { it % 2 == 0 } | Contare le corrispondenze |
list.find { it > 2 } | Prima corrispondenza oppure null |
list.sortedBy { it.length } | Ordinare in base a una chiave |
list.groupBy { it.first() } | Raggruppare in una Map |
list.distinct() | Rimuovere i duplicati |
list.fold(0) { acc, x -> acc + x } | Ridurre con un valore iniziale |
list.zip(other) | Accoppiare due liste |
list.flatMap { it.toList() } | Mappare e poi appiattire |
Classi e data class
| Sintassi | Significato |
|---|
class User(val name: String, var age: Int) | Classe con costruttore primario e proprietà |
val u = User("Ada", 36) | Creare un'istanza (senza new) |
u.name, u.age = 37 | Leggere / scrivere proprietà |
data class Point(val x: Int, val y: Int) | equals, hashCode, toString, copy gratis |
p.copy(y = 5) | Copiare cambiando alcune proprietà |
val (x, y) = p | Dichiarazione con destructuring |
open class Base, class Sub : Base() | Ereditarietà (le classi sono final per impostazione predefinita) |
override fun toString() = "..." | Sovrascrivere un membro |
object Config { val debug = true } | Singleton |
companion object { fun create() = User("", 0) } | Membri simili a static |
enum class Color { RED, GREEN } | Enum |
sealed class Result | Gerarchia di classi ristretta, esaustiva in when |
interface Shape { fun area(): Double } | Interfaccia |
Gestione degli errori
| Sintassi | Significato |
|---|
try { ... } catch (e: Exception) { ... } | Catturare un'eccezione |
try { ... } finally { ... } | Eseguire sempre la pulizia |
val n = try { s.toInt() } catch (e: NumberFormatException) { 0 } | try come espressione |
throw IllegalArgumentException("bad") | Lanciare un'eccezione |
require(x > 0) { "x must be positive" } | Controllo sugli argomenti (lancia IllegalArgumentException) |
check(ready) { "not ready" } | Controllo sullo stato (lancia IllegalStateException) |
s.toIntOrNull() | Restituire null invece di lanciare un'eccezione |
runCatching { risky() }.getOrDefault(0) | Racchiudere una chiamata in un Result |
Scope function
Cinque piccoli helper per lavorare con un oggetto dentro un blocco.
| Sintassi | Significato |
|---|
x.let { it + 1 } | it è l'oggetto, restituisce il risultato del blocco |
x.run { this + 1 } | this è l'oggetto, restituisce il risultato del blocco |
x.apply { field = 1 } | this è l'oggetto, restituisce l'oggetto |
x.also { println(it) } | it è l'oggetto, restituisce l'oggetto |
with(x) { field } | Non è un'estensione; this è x, restituisce il risultato del blocco |
x?.let { ... } | Il modo idiomatico per controllare null e usare il valore |
Tutta la sintassi di Kotlin che usi, in una sola pagina. Questa cheat sheet di Kotlin è un riferimento rapido per il linguaggio dietro Android e buona parte della JVM moderna: dichiarare variabili, gestire i null in sicurezza, ramificare con when, ciclare sui range, scrivere funzioni e lavorare con liste e map.
Tutto quello che trovi qui è Kotlin standard e gira allo stesso modo su JVM, Android e Kotlin Multiplatform. Copia quello che ti serve oppure provalo dal vivo nel playground Kotlin: incolla un frammento, premi Run e guarda l'output nel browser.