Storia della questione:
L'operatore Elvis (?:) è stato introdotto in Kotlin come un modo conciso e sicuro per gestire valori nullable. Ha preso il suo nome per la somiglianza con la pettinatura di Elvis Presley, se visto di lato. L'obiettivo è liberarsi dal codice standard come if (a != null) a else b e rendere lo sviluppo quotidiano più comodo.
Problema:
L'accesso diretto a un valore che può essere null porta a un errore di esecuzione (NullPointerException). Pertanto, è necessario uno strumento che consenta di sostituire elegantemente valori di default quando la variabile risulta null.
Soluzione:
L'operatore Elvis è applicabile ai tipi nullable. Se l'espressione a sinistra dell'operatore non è null, viene restituita, altrimenti viene restituita l'espressione a destra. Questo rende il codice più compatto e sicuro.
Esempio di codice:
fun getLength(str: String?): Int { return str?.length ?: 0 } val result = getLength(null) // result == 0 val result2 = getLength("Hello") // result2 == 5
Caratteristiche principali:
Cosa succede se a destra dell'operatore Elvis c'è un'espressione con effetti collaterali? Viene sempre eseguita?
No! L'espressione a destra viene calcolata solo se a sinistra è risultato null. Questo può avere un ruolo importante se la funzione ha effetti collaterali o calcoli "costosi".
Esempio di codice:
var called = false val x: String? = "test" val y = x ?: run { called = true; "default" } // called sarà false, perché run non verrà nemmeno eseguito
È possibile utilizzare l'operatore Elvis per sollevare eccezioni?
Sì, in Kotlin è possibile scrivere così:
fun getLengthStrict(str: String?): Int = str?.length ?: throw IllegalArgumentException("str è null")
Se str è null, verrà sollevata un'eccezione. Si tratta di un meccanismo utile di validazione dei dati.
È possibile "incatenare" più operatori Elvis?
Sì, questo è un approccio comune per i fallback:
val name = fromDatabase ?: fromCache ?: "Unknown"
Questa espressione restituirà il primo valore NON null o la stringa "Unknown".
Annidamento multi-livello di controlli null tramite Elvis:
val title = a?.b?.c?.d?.e ?: defaultTitle
Pro:
Contro:
Decomposizione esplicita per passaggi, nomi di variabili comprensibili:
val deepValue = a?.b val deeperValue = deepValue?.c?.d ?: default
Pro:
Contro: