La versione 1.0 di Kotlin è di­spo­ni­bi­le solo dal 2016, ma è già molto ap­prez­za­ta perché rap­pre­sen­ta una valida al­ter­na­ti­va a Java. Questo lin­guag­gio di pro­gram­ma­zio­ne basato su oggetti è stato svi­lup­pa­to da JetBrains, una società ceca di sviluppo software. Convince molte persone per il suo carattere snello e per il numero ridotto di errori di runtime che produce, in par­ti­co­la­re le temute Null­Poin­te­rEx­cep­tions. Kotlin è par­ti­co­lar­men­te ap­prez­za­to nello sviluppo di ap­pli­ca­zio­ni Android, ma anche come punto di partenza per le ap­pli­ca­zio­ni Ja­va­Script, dove il giovane lin­guag­gio di pro­gram­ma­zio­ne gode di enorme po­po­la­ri­tà.

Kotlin è fon­da­men­tal­men­te basato su Java: sebbene i due linguaggi di pro­gram­ma­zio­ne non siano com­pa­ti­bi­li, Kotlin viene con­ver­ti­to in bytecode, che può essere letto da una Java Virtual Machine (JVM).

Istru­zio­ni per usare Kotlin con esempi

Per iniziare con Kotlin potete scaricare il com­pi­la­to­re dal sito ufficiale. La cosa migliore è uti­liz­za­re un ambiente di sviluppo (IDE), come ad esempio IntelliJ IDEA (sempre di JetBrains), Eclipse (con relativo plug-in), NetBeans e Android Studio, che sup­por­ta­no Kotlin.

Consiglio

I pro­dut­to­ri di Kotlin mettono a di­spo­si­zio­ne una sandbox online dove potete provare tutti gli esempi.

Pacchetti (packages)

Al­l'i­ni­zio di un progetto dovete importare i pacchetti necessari per la sua rea­liz­za­zio­ne e definire il pacchetto su cui state lavorando. I pacchetti con­ten­go­no classi e funzioni.

package test.bar
import foo.bar
import footoo.bar as footoo

Per evitare problemi con nomi identici è possibile ri­no­mi­na­re i pacchetti in Kotlin con as. L'as­se­gna­zio­ne dei nomi ai pacchetti non deve seguire la struttura di directory in cui si trovano, ma si rac­co­man­da comunque questa prassi per motivi di chiarezza.

N.B.

Kotlin carica au­to­ma­ti­ca­men­te i pacchetti più im­por­tan­ti in ogni progetto.

A dif­fe­ren­za di Java, Kotlin permette anche di importare singole funzioni da altri pacchetti. Per farlo dovete spe­ci­fi­ca­re il percorso corretto:

import foo.bar.myFunction

La funzione può quindi essere uti­liz­za­ta nor­mal­men­te.

Consiglio

Le righe di codice in Kotlin non ri­chie­do­no più l'uso di ter­mi­na­to­ri, come un punto e virgola.

Variabili

Kotlin prevede due diversi tipi di variabili: quelle che indicano un ri­fe­ri­men­to im­mu­ta­bi­le e non sono mo­di­fi­ca­bi­li, in­tro­dot­te con val, e quelle il cui valore può essere mo­di­fi­ca­to nel corso del programma, che vengono in­tro­dot­te con var.

val name = "Clara Oswald"
var age = 22

A dif­fe­ren­za del nome, che è costante, l'età può essere mo­di­fi­ca­ta, ad esempio in una funzione.

N.B.

In questo esempio, Kotlin ha impostato au­to­no­ma­men­te il valore della variabile. È anche possibile eti­chet­ta­re spe­ci­fi­ca­men­te questi tipi di base.

Tipi di base (basic types)

Kotlin lavora con specifici tipi di variabili e classi. In Kotlin ogni tipo consiste in un oggetto, il che lo rende leg­ger­men­te diverso da Java. Mentre il lin­guag­gio di pro­gram­ma­zio­ne più vecchio deve prima im­pac­chet­ta­re i tipi primitivi in una classe wrapper per renderli oggetti, in Kotlin non è ne­ces­sa­rio perché tutti i tipi sono già oggetti.

Numeri (numbers)

In Kotlin è possibile inserire numeri senza un marcatore specifico: il com­pi­la­to­re capisce che si tratta di valori numerici. Le virgole sono indicate da punti. È possibile uti­liz­za­re anche numeri esa­de­ci­ma­li. Per una migliore leg­gi­bi­li­tà è possibile vi­sua­liz­za­re i se­pa­ra­to­ri decimali mediante trattini bassi. Kotlin conosce diversi tipi di numeri, ognuno dei quali può avere una di­men­sio­ne massima diversa:

  • Long: 64 bit
  • Int: 32 bit
  • Short: 16 bit
  • Byte: 8 bit
  • Double: 64 bit
  • Float: 32 bit

Double e Float sono numeri a virgola mobile che si com­por­ta­no di­ver­sa­men­te dai numeri a virgola fissa nei calcoli complessi. Come tutti i tipi, è possibile con­tras­se­gna­re con­cre­ta­men­te i numeri nel codice.

val myNumber: Long = 40

È possibile con­ver­ti­re un numero di un tipo in un altro.

val myInt = 600
val myLong= myInt.toLong()

Il comando toLong converte il valore Int in un valore Long. Il comando funziona allo stesso modo per gli altri tipi di numeri.

String

Quando parliamo di string in­ten­dia­mo una parola o una frase intera, ovvero una stringa di caratteri. Per uti­liz­zar­li in Kotlin inserite il testo scritto tra vir­go­let­te doppie. Se volete inserire più righe di testo, sono ne­ces­sa­rie tre vir­go­let­te doppie sia al­l'i­ni­zio che alla fine (Raw String).

val myString = "Questo è uno string singolo."
val myLongString = """Questo è uno string
su più righe."""

Come in molti altri linguaggi di pro­gram­ma­zio­ne, anche Kotlin supporta le sequenze di escape: an­te­po­nen­do un backslash davanti a un carattere indicate che questo non ap­par­tie­ne alla stringa vera e propria e che deve essere trattato come un carattere di controllo. Con l'aiuto del backslash potete inserire nella stringa anche caratteri che hanno un si­gni­fi­ca­to diverso in Kotlin. Queste sono le sequenze di escape possibili:

  • \t: tab
  • \b: backspace
  • \n: nuova riga
  • \r: carriage return (ritorno a capo)
  • \': vir­go­let­ta singola
  • \": vir­go­let­ta doppia
  • \\: backslash
  • \$: simbolo del dollaro

Il simbolo del dollaro viene uti­liz­za­to nelle stringhe per inserire me­ta­ca­rat­te­ri, i quali possono essere impostati come variabili in un passaggio pre­ce­den­te. Il me­ta­ca­rat­te­re viene quindi so­sti­tui­to nel­l'out­put da un valore effettivo.

val author = "Sandra"
val myString = "Questo testo è di $autore"

Caratteri (cha­rac­ters)

In aggiunta agli string per i singoli caratteri Kotlin fornisce anche il tipo di dati speciale character. Questi vanno tuttavia inseriti tra vir­go­let­te singole piuttosto che tra quelle doppie.

var model = 'A'

Booleano

Il basic type boolean può assumere soltanto due valori, vero (true) o falso (false).

Array

In Kotlin un array è una raccolta di dati. Un array è formato da arrayOf() o Array(). La prima funzione è semplice:

val myArray1 = arrayOf(0, 1, 2, 3, 4, 5)

In questo modo viene creato un array con le cifre da 1 a 5. In queste raccolte possono essere incluse anche altri tipi di string e booleani, anche misti. Se si vuole limitare l'array a un solo tipo, lo si specifica nella funzione.

val myArray2 = arrayOf<int>(10, 20, 30)</int>
val myArray3 = booleanArrayOf(true, true, false)

Il co­strut­to­re Kotlin Array() è più complesso: qui è ne­ces­sa­rio spe­ci­fi­ca­re anche la lunghezza e una funzione lambda.

val myArray4 = Array(6, { i -> i })

Il co­strut­to­re crea un array a sei cifre partendo da zero: 0, 1, 2, 3, 4, 5.

N.B.

L'ar­go­men­to relativo a co­strut­to­ri e lambda sarà ap­pro­fon­di­to più avanti.

Ogni in­se­ri­men­to in un array è in­di­ciz­za­to e può essere chiamato tramite questo indice. A tale scopo vengono uti­liz­za­te le parentesi quadre nelle quali viene spe­ci­fi­ca­ta la posizione del­l'in­se­ri­men­to nel­l'e­len­co.

fun main() {
	val myArray5 = arrayOf("Jan", "Maria", "Samuel")
	println(myArray5[2])
}
N.B.

Il risultato della funzione in questo caso sarà "Samuel", dato che il conteggio inizia da 0.

Operatori

Come molti altri linguaggi di pro­gram­ma­zio­ne, anche Kotlin lavora con diversi operatori che potete integrare nel vostro codice sorgente. Questi includono operatori ma­te­ma­ti­ci (+, -, *, /, %), operatori di confronto (<, >, <=, >=, ==, !=) e operatori logici (&&, ||, !). Stret­ta­men­te legati agli operatori sono le keyword, ovvero termini che hanno un si­gni­fi­ca­to fisso in Kotlin che non può essere cambiato.

Consiglio

Nella do­cu­men­ta­zio­ne ufficiale di Kotlin potete trovare una lista completa di tutte le keyword e degli operatori.

Range

In Kotlin un range descrive un tipo che va da un de­ter­mi­na­to punto a un altro. Per creare un range si utilizza l'o­pe­ra­to­re .. o le funzioni rangeTo() o downTo(). La variante con i due punti è in­cre­men­ta­le, mentre con le due funzioni si definisce una direzione.

val range1 = 1..5
val range2 = 1.rangeTo(5)
val range3 = 5.downTo(1)

In queste versioni semplici sono suf­fi­cien­ti step con valore 1 per creare un range. Se invece volete mo­di­fi­ca­re il valore degli step dovete uti­liz­za­re la relativa funzione step.

val range4 = 0..10 step(2)

Per in­di­riz­za­re dati singoli nel range, uti­liz­za­te l'o­pe­ra­to­re in. In questo modo potete per esempio creare espres­sio­ni o cicli. Per ve­ri­fi­ca­re se un valore non ap­par­tie­ne al range viene uti­liz­za­to l'o­pe­ra­to­re !in.

val range5 = 0..10
fun main() {
	for (n in range5) {
		println(n)
	}
	if (7 in range5) {
		println("yes")
	}
	if (12 !in range5) {
		println("no")
	}
}
N.B.

L'ar­go­men­to relativo a funzioni, cicli ed espres­sio­ni sarà ap­pro­fon­di­to più avanti.

Funzioni (functions)

Le funzioni in Kotlin vengono sempre create mediante il comando fun. Dopodiché vengono definiti il nome della funzione, gli argomenti contenuti e il modo in cui agisce.

fun div(a: Int, b: Int): Int {
	return a/b
}
fun main() {
	println(div(100, 2))
}

In­nan­zi­tut­to definiamo la funzione div (che sta per divisione) mediante due parametri Int, a e b. Compito della funzione è quello di fornirci il risultato della divisione tra a e b, sempre sotto forma di variabile Int. In seguito chiamiamo la funzione pre­ce­den­te­men­te definita nella funzione main, le as­se­gnia­mo valori concreti e vi­sua­liz­zia­mo il risultato nella console mediante println (print line). Kotlin esegue il contenuto della funzione main() au­to­ma­ti­ca­men­te. Questa funzione rap­pre­sen­ta il punto di partenza in un programma Kotlin.

Fatto

Kotlin non accetta comandi oltre alle funzioni. Sono ammesse solo di­chia­ra­zio­ni.

In Kotlin è possibile rap­pre­sen­ta­re le funzioni composte da una sola riga di codice in modo sem­pli­fi­ca­to. Invece di aprire una parentesi graffa, scrivere una nuova riga e chiudere la parentesi, si usa un segno uguale e si rinuncia al comando return.

fun div(a: Int, b: Int): Int = a/b
fun main() = println(div(100, 2))

Quando definite una funzione potete indicare valori di default per evitare che parametri mancanti causino errori. In questo modo se lasciate vuoti i ri­spet­ti­vi parametri, verranno uti­liz­za­ti i valori di default.

fun div(a: Int = 10, b: Int = 5): Int = a/b
fun main() = println(div())

Lambda

Una funzione lambda (o funzione anonima) è una funzione che non ap­par­tie­ne ad alcuna classe o oggetto. Le funzioni lambda vengono inserite di­ret­ta­men­te in altre funzioni o variabili e chiamate senza l'uso della keyword fun. Le funzioni lambda vengono so­stan­zial­men­te uti­liz­za­te e create come le variabili del tipo val.

fun main() {
	val myMessage = { println("Hello world!") }
	myMessage()
}

In Kotlin le espres­sio­ni lambda devono essere inserite sempre tra parentesi graffe e possono elaborare anche argomenti di funzioni. Queste sono con­tras­se­gna­te da una freccia che separa i parametri dal nucleo del­l'e­spres­sio­ne.

fun main() {
    val div = {a: Int, b: Int -> a/b}
    println(div(6,2))
}

Classi (classes)

Proprio come in Java, anche in Kotlin le classi sono raccolte di dati e funzioni. Per definire una classe è suf­fi­cien­te inserire la keyword class. In seguito è possibile ag­giun­ge­re in­for­ma­zio­ni alla classe.

class Tardis {
	var year: Int
	var place: String
	constructor(year: Int, place: String) {
		this.year = year
		this.place = place
	}
}

In Kotlin il co­strut­to­re rap­pre­sen­ta una funzione ne­ces­sa­ria per la creazione di oggetti. A tale scopo il lin­guag­gio di pro­gram­ma­zio­ne distingue tra co­strut­to­ri primari e secondari. I co­strut­to­ri primari sono una pratica scrittura ab­bre­via­ta, mentre quelli secondari ricordano molto la scrittura di altri linguaggi a oggetti, come Java. L'esempio sum­men­zio­na­to mostra la seconda variante.

È possibile comunque omettere il co­strut­to­re se­con­da­rio e inserire al suo posto un co­strut­to­re primario, che viene spe­ci­fi­ca­to di­ret­ta­men­te nel­l'in­te­sta­zio­ne della classe e ne indica, allo stesso tempo, i parametri, riducendo no­te­vol­men­te il numero di righe di codice.

class Tardis constructor(var year: Int, var place: String)

Se non volete spe­ci­fi­ca­re ulteriori istru­zio­ni in merito alla vi­si­bi­li­tà (public, private, protected), potete omettere del tutto la keyword.

class Tardis (var year: Int, var place: String)

Tutti e tre gli esempi di codice re­sti­tui­sco­no lo stesso risultato.

Potete adesso inserire la classe nel resto del vostro testo sorgente e ali­men­tar­la con valori concreti.

val tardis1 = Tardis(2133, "Dunlop Station")
val tardis2 = Tardis(1885, "Northhampton")

Come per la maggior parte dei linguaggi a oggetti potete accedere alle proprietà e ai metodi di un oggetto po­si­zio­nan­do un punto e il nome della proprietà o del metodo dopo quello del­l'og­get­to stesso.

class Tardis (var year: Int, var place: String)
val tardis1 = Tardis(2133, "Dunlop Station")
val tardis2 = Tardis(1885, "Northhampton")
fun main() {
    println(tardis1.year)
}

Una par­ti­co­la­ri­tà di Kotlin sono le data class. Questo tipo di classe ha l'unico scopo di im­ma­gaz­zi­na­re dati. A tale scopo è, in genere, suf­fi­cien­te una riga di codice.

data class User (var username: String, var name: String, var age: Int)

Questa classe può essere uti­liz­za­ta di­ret­ta­men­te.

data class User (var username: String, var name: String, var age: Int)
fun main() {
    val user1 = User ("River Song", "Melody Pond", 200)
    println("Username: " + user1.username)
    println("Name: " + user1.name)
    println("Age: " + user1.age)
}

Oggetti (objects)

In Kotlin gli oggetti sono istanze che possono essere definite in un de­ter­mi­na­to modo una sola volta (singleton). In genere con­ten­go­no variabili e funzioni. Per creare un oggetto è so­li­ta­men­te suf­fi­cien­te una sola riga di codice, come anche per le classi. L'oggetto creato sarà comunque vuoto e i relativi contenuti saranno aggiunti al suo corpo.

object myObject {
	fun sum(a: Int, b: Int): Int {
		return a+b
	}
}

Cicli (loop)

In Kotlin potete scegliere tra tre diverse tipologie di ciclo: while, do..while e if, che si com­por­ta­no esat­ta­men­te come le loro con­tro­par­ti in altri linguaggi di pro­gram­ma­zio­ne. Un ciclo di tipo while viene eseguito finché una de­ter­mi­na­ta con­di­zio­ne resta ve­ri­fi­ca­ta.

fun main() {
    var n = 1
    while (n <= 10) {
        println(n++)
    }
}

Il ciclo do..while si comporta in modo analogo a quello con while. La dif­fe­ren­za sta nel fatto che in questo caso il ciclo viene eseguito almeno una volta, dato che il controllo della con­di­zio­ne viene eseguito soltanto al termine del ciclo.

fun main() {
    var n = 1
    do {
        n++
    }	
    while (n < 1)
    println(n)
}

Il ciclo for viene eseguito finché la con­di­zio­ne è vera.

val myRange = 0..10
fun main() {
	for (n in myRange) {
		print("$n ")
	}
}

Con­di­zio­ni (con­di­tions)

Kotlin adotta tre diverse pos­si­bi­li­tà per eseguire istru­zio­ni o di­ra­ma­zio­ni con­di­zio­na­li: if, if..else e when. Mediante l'e­spres­sio­ne if, il computer esegue un'i­stru­zio­ne se la con­di­zio­ne è vera.

val whoCompanion = arrayOf("Bill Potts", "Clara Oswald", "Amy Pond", "Martha Jones", "Donna Noble", "Rose Tyler")
fun main() {
    if ("Rose Tyler" in whoCompanion) {
        print("yes")
    }
}

Con else ag­giun­ge­te un'azione che deve essere eseguita qualora la con­di­zio­ne non fosse vera.

val whoCompanions9 = arrayOf("Rose Tyler")
val whoCompanions10 = arrayOf("Martha Jones", "Donna Noble", "Rose Tyler")
val whoCompanions11 = arrayOf("Clara Oswald", "Amy Pond")
val whoCompanions12 = arrayOf("Bill Potts", "Clara Oswald")
fun main() {
    var whoCompanion = "Clara Oswald"
    if (whoCompanion in whoCompanions9) {
        print("yes")
    }
    else {
        print("no")
    }
}

Infine l'e­spres­sio­ne when è una par­ti­co­la­ri­tà di Kotlin: a seconda delle con­di­zio­ni vengono eseguite azioni diverse. L'e­spres­sio­ne when somiglia quindi a quello che in altri linguaggi di pro­gram­ma­zio­ne viene definito switch, ma lavora in modo più preciso.

Nel corpo di when inserite i diversi casi di controllo, che sono sempre collegati a una de­ter­mi­na­ta variabile.

var age = 17
fun main() {
    when {
     	age > 18 -> println("Sei troppo grande!")
     	age == 18 -> println("Già adulta!")
     	age == 17 -> println("Benvenuta!")
     	age <= 16 -> println("Sei troppo giovane!")
    }
}

Se l'ar­go­men­to viene tra­sfe­ri­to di­ret­ta­men­te a when non è ne­ces­sa­rio ripeterlo ogni volta nel corpo. Una singola con­di­zio­ne può inoltre eseguire diverse azioni. A tale scopo, create mediante parentesi graffe un nuovo corpo e per evitare casi ina­spet­ta­ti uti­liz­za­te else.

fun multi(a: Int, b: Int, c: Int): Int {
    return a*b*c
}
fun main() {
    val d = "yes"
    when (d) {
        "no" -> println("Nessun calcolo")
        "yes" -> {
            println("Avvia calcolo") 
            println(multi(5, 2, 100))
            println("Calcolo terminato")
        }
    else -> println("Inserimento errato")    
    }
}

Nul­la­bi­li­tà

Un aspetto molto sco­rag­gian­te nella pro­gram­ma­zio­ne con Java è l'errore Null­Poin­te­rEx­cep­tion, che si presenta quando si chiama un oggetto con valore null. Kotlin aggira questo problema impedendo di default alle variabili di assumere il valore null. Se si ve­ri­fi­cas­se questa con­di­zio­ne, com­pa­ri­reb­be già durante la com­pi­la­zio­ne la seguente nota: "Null can not be a value of a non-null type String" o un avviso simile.

Ci sono però momenti in cui si intende uti­liz­za­re il valore null in­ten­zio­nal­men­te. Per questi casi, Kotlin utilizza l'operatore di chiamata sicura ?.

fun main() {
	var password: String? = null
	print(password)
}

In questo modo indicate espli­ci­ta­men­te a Kotlin che il valore null è am­mis­si­bi­le. Il programma re­sti­tui­sce null. Se invece volete in­di­riz­za­re una proprietà par­ti­co­la­re della variabile, dovete nuo­va­men­te ricorrere al­l'o­pe­ra­to­re di chiamata sicura.

fun main() {
	var password: String? = null
	print(password?.length)
}

Anche questo codice re­sti­tui­rà null, ma senza produrre errori o com­pro­met­te­re il fun­zio­na­men­to del programma. Un modo più elegante sarebbe indicare un valore al­ter­na­ti­vo. A tale scopo potete usare l'operatore elvis (?:), così chiamato per la sua so­mi­glian­za a una faccina sor­ri­den­te con il ciuffo.

fun main() {
    val firstName = null
    val lastName = "Pond"
	val name: String = firstName?: "Nome mancante" + " " + lastName?: "Cognome mancante"
	print(name)
}

In questo esempio vengono vi­sua­liz­za­te delle note nel caso in cui una variabile abbia il valore null.

Vai al menu prin­ci­pa­le