[Kotlin Tip] Null safety
Una delle caratteristiche di Kotlin, tra le più interessanti, è la cosiddetta null safety, ovvero la verifica in fase di compilazione delle null reference presenti nel nostro codice.
Avete presente quelle simpatiche eccezioni di tipo NullPointerException
che saltano fuori a runtime, quando meno ce lo aspettiamo, e ci fanno esclamare “accipicchia!” (o qualcosa di simile…), con tono un po’ imbarazzato?
Ecco, Kotlin elimina (quasi) completamente quest’imbarazzo tramite la definizione di tipi nullable e non-null.
Cosa significa?
Significa che avremo la possibilità di dichiarare variabili che possono essere valorizzate con null
ed altre che non ammettono questo valore. Per dichiarare una variabile nullable sarà sufficiente aggiungere un ?
subito dopo il tipo della stessa.
Un esempio:
la dichiarazione con assegnazione appena vista genererà un errore di compilazione in quanto si sta tentando di assegnare il valore null
ad un campo String
non-null. Per correggere l’errore dovremo invece dichiarare la variabile in questo modo:
La cosa interessante è il fatto che questa verifica avvenga in fase di compilazione, riducendo quasi totalmente la possibilità d’introdurre erroneamente null reference nel nostro codice.
Lavorare con i tipi nullable
Compresa la differenza tra le due tipologie… di tipi, c’interessa capire come lavorare con esse e in particolare con i tipi nullable.
Supponiamo ad esempio di aver dichiarato un membro nullable nella nostra classe e di voler recuperare il valore di una sua property (o di voler invocare un suo metodo):
L’accesso alla proprietà prop
, tramite il classico operatore .
funzionerebbe correttamente per un obj
dichiarato come non-null, ma nel nostro caso genererà un errore di compilazione. Qualcosa di questo tipo:
Error:(x, y) Kotlin: Only safe (?.) or non-null asserted (!!.) calls
are allowed on a nullable receiver of type MyType?
Che fare, dunque?
Dalla nostra esperienza con Java, sappiamo bene che è buona norma verificare prima di tutto se il nostro oggetto è una null reference, proprio per evitare una NullPointerException
durante questo tipo di operazioni.
Anche in Kotlin abbiamo la possibilità di effettuare un classico null check tramite l’istruzione if
:
Come vedete, dopo il null check possiamo invocare prop
come se fosse non-null (con il .
), questo grazie allo smart cast eseguito dal compilatore.
Nota Lo smart cast da nullable a non-null funziona solo per oggetti immutabili.
Kotlin però permette di fare tutto ciò in modo ancora più espressivo grazie a due operatori formidabili!
Gli operatori Safe Call ed Elvis
Un approccio alternativo al classico null check ce lo suggerisce l’errore di compilazione visto precedentemente.
Per accedere una proprietà o invocare un metodo di un campo potenzialmente nullo possiamo infatti sfruttare l’operatore ?.
(safe call operator):
Molto semplicemente, questa espressione sta a significare: restituisci il valore di prop
se obj
è diverso da null
, altrimenti restituisci proprio null
.
Allo stesso modo, possiamo sfruttare l’operatore safe call anche per invocare metodi:
In particolare, in questo caso il metodo verrà eseguito solamente se nessuno degli oggetti/proprietà nella catena d’invocazioni è uguale a null
.
Come visto, quindi, l’operatore ?.
permette di recuperare in modo sicuro il valore di una proprietà o, quando questo non fosse possibile, di ottenere un null
(invece di una fastidiosa eccezione…).
Ma se volessimo fornire un valore alternativo, non nullo?
In tal caso entra in gioco l’operatore Elvis (?:
), col suo mitico ciuffo! 😃
Analogamente a quanto visto con l’approccio if/else
, possiamo scrivere qualcosa di simile:
In questo modo, quando obj
o prop
risulteranno null
, il valore "no value"
verrà assegnato alla variabile. Fico, no?
L’operatore non-null assertion
Vediamo infine un’opzione che in generale andrebbe evitata in un linguaggio munito di null safety, ma che in alcuni casi potrebbe tornare utile.
Una delle poche situazioni, usando Kotlin, in cui ci ritroveremo faccia a faccia con una NullPointerException
è in corrispondenza di espressioni in cui si fa uso dell’operatore !!
(non-null assertion operator).
Applicando !!
andiamo a forzare la conversione di un tipo nullable nel suo corrispondente non-null. In questo modo però ci esponiamo alla possibilità che venga sollevata un’eccezione in caso di null reference. Due esempi:
Nel primo caso l’asserzione è corretta: la variabile i
contiene un valore diverso da null
, dunque l’invocazione del metodo toFloat
va a buon fine. Nel secondo caso invece, avendo forzato la conversione di una variabile effettivamente valorizzata a null
, otterremo la tanto odiata eccezione…
In conclusione
La null safety di Kotlin è uno strumento davvero utile, che ci tira fuori da un bel po’ di guai, ma che va usato con consapevolezza.
L’utilizzo idiomatico degli operatori ?.
e ?:
rende il tutto più snello e divertente, ma bisogna sempre far attenzione alla leggibilità del codice che, a mio parere, deve rimanere una delle priorità di ogni programmatore saggio.
A presto,
David