In Kotlin inline class (a partire da Kotlin 1.5 — termine "value class"), consentono di creare wrapper sui tipi con costi minimi. Durante la compilazione, tali classi vengono sostituite, sotto il cofano, dal loro valore interno (value) per evitare il sovraccarico della creazione di oggetti.
Limitazioni e caratteristiche:
=== non funziona come al solito).Esempio:
@JvmInline value class UserId(val value: String) fun getUser(id: UserId) { println("Loading user with id: ${id.value}") } val id = UserId("XYZ") getUser(id) // Sotto il cofano funziona semplicemente con String!
Quando utilizzare:
È possibile ereditare value class o utilizzarla in gerarchia di interfacce/classi astratte?
Risposta: No, la value class non può ereditare altre classi (a parte le interfacce), non può essere aperta per eredità, non consente il blocco init e altri campi non statici. L'unica opzione disponibile è implementare interfacce.
Esempio:
interface Validatable { fun isValid(): Boolean } @JvmInline value class Email(val raw: String) : Validatable { override fun isValid() = raw.contains("@") }
Storia
Un'app Android ha improvvisamente aumentato il tempo di avvio dopo l'aggiunta di value class ai parametri Parcelable: si è scoperto che un @Parcelize errato con value class portava a boxing/unboxing in ogni fase della serializzazione, vanificando i vantaggi dell'inlining.
Storia
Un microservizio ha iniziato a utilizzare attivamente value class per UserId e ProductId per la sicurezza dei tipi, ma in molti casi le funzioni generiche richiedevano la riflessione, che non funzionava con "il wrapper". I test unitari hanno iniziato a fallire inaspettatamente, si sono verificati ClassCastException.
Storia
Il codice migrato da Java ha iniziato a sostituire le classi di dominio interne con value class per l'ottimizzazione, ma il loro utilizzo come campi nullable ha portato a unexpected null pointer exception, poiché la value class può essere null solo se il valore esterno è anch'esso null, rompendo così i vecchi invarianti.