Kotlin Language

Null safety

Dal momento che Kotlin vuole eliminare molte delle lacune presenti in Java, ecco che questo paragrafo risulta particolarmente azzeccato. La sigla NPE (Null Pointer Exception) è ben tristemente nota a chi programma in Java intendendosi con essa l'uso di un puntatore nullo. Come detto i programmatori Java ben conoscono questo problemi che tanti danni e grattacapi ha causato e causa tuttora. Kotlin, come altri linguaggi di moderna creazione, cerca di eliminare radicalmente queste problematiche. Cominciamo dall'esempio più semplice, preso dal sito ufficiale:

  Esempio 7.1
1
2
3
4
5
fun main(args : Array<String>)
{
var a : String = "AAA";
a = null;
}

Come è immediato verificare la riga 4 non compila; il perchè è evidente, assegniamo il valore null ad un tipo, String, che, non accetta di default questo valore. Ovviamente questa apparente limitazione è stata pensata appunto per evitare di avere il valore nullo assegnato ad una stringa e quindi viene tolta la possibilità di incappare in una stringa nulla (pensateci un attimo e vedrete che è cosa buona). Per poter rendere legale l'istruzione alla riga 4 dovremmo riscrivere quella alla 3 come segue:

var a : String? = "AAA";

con l'aggiunta di quel ? che rende "nullable" la variabile a. Così facendo il compilatore non si lamenta. Tuttavia, evidentemente, resta aperta una importante questione: come è garantita la null-safety in quel caso? Vediamo cosa succede con un esempio un po' più ampio:

  Esempio 7.2
1
2
3
4
5
6
7
fun main(args : Array<String>)
{
var a : String = "AAA";
var b : String? = "BBB";
val la = a.length();
val lb = b.length();
}

Il programma 7.2 non compila e il messaggio d'errore che riceverete se prova a darlo in pasto al compilatore è molto eloquente:

Kotlin: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type jet.String?

capito? Kotlin si accorge che avete cercato di effettuare un'operazione di assegnamento tramite un tipo non sicuro e ve lo segnala bloccando la compilazione. Quindi bisogna fare un po' di lavoro affinchè questa assegnamento alla riga 6 possa essere portato a termine. Un modo è procedere modificando la linea in parola come segue:

val lb = b?.length();

In questo caso lb sarà di tipo Int? e il suo valore potrà essere un intero o null a seconda che b sia di lunghezza significativa o null. Non vi sarà eccezione sollevata e, inoltre, il programmatore in un certo senso prende atto di consentire l'ammissibilità del valore null attraverso l'attribuzione di ? alla variabile.

Un altro sistema, come indicato anche dall'errore segnalato dal tentativo di esecuzione del codice 7.2, fa uso del cosiddeto Elvis operator. Cambiamo al riga 6 come segue:

val lb = b?.length() ?: -1

Se l'espressione a sinistra del second ? è non nulla viene restituito il valore altrimenti si va con quanto sta a destra. In casi in cui null non vada proprio bene ma possa comunque capitare tra i piedi secondo me questo è il sistema migliore ed anche più elegante.

Da ultimo, se siete nostalgici della NPE potete istruire al compilatore a rendervela disponibile, attraverso l'operatore !!

val lb = b!!.length();

che, se accade, vi solleva la tanto desiderata NPE che dovrà essere adeguatamente gestita.