Clase de Valoare și Optimizare Zero-Allocation în Kotlin: @JvmInline value class în Kotlin

Clase și obiecte Kotlin 2.0

Ghid complet pentru Value Classes în Kotlin: eliminarea alocărilor de memorie pe Heap cu @JvmInline, împachetarea tipizată sigură a identificatorilor (Domain-Driven Design) și inlining ca tip primitiv la compilare.

Sintaxă
@JvmInline value class UserId(val id: Long) | value class Password(val hash: String)

În proiectarea orientată pe domeniu (Domain-Driven Design – DDD), folosirea tipurilor primitive brute (cum ar fi Long sau String) pentru identificatori este o practică riscantă: dacă o funcție primește (userId: Long, orderId: Long), inversarea accidentală a parametrilor va compila fără erori, producând bug-uri catastrofale de date la runtime (Primitive Obsession).

Totuși, împachetarea fiecărui ID într-o clasă obișnuită (data class UserId(val id: Long)) introduce o penalizare severă: milioane de alocări pe Heap, presiune continuă pe Garbage Collector și pierderea eficienței cache-ului CPU. Soluția modernă în Kotlin este @JvmInline value class.

Definirea și Utilizarea unei Clase de Valoare (Zero-Allocation)
// Clasa de valoare deține exact o singură proprietate imutabilă:
@JvmInline
value class UtilizatorId(val valoare: Long) {
    init {
        require(valoare > 0) { "ID-ul trebuie să fie un număr pozitiv!" }
    }

    // Poate conține metode și proprietăți calculate:
    fun esteAdmin(): Boolean = valoare == 1L
}

@JvmInline
value class ComandaId(val valoare: Long)

public class ServiciuVanzari {
    // Tipizare strictă la compilare:
    fun proceseazaComanda(userId: UtilizatorId, comandaId: ComandaId) {
        println("Procesare comanda ${comandaId.valoare} pentru utilizatorul ${userId.valoare}");
    }
}

fun main() {
    val uId = UtilizatorId(1042L)
    val cId = ComandaId(9812L)

    val serviciu = ServiciuVanzari()
    serviciu.proceseazaComanda(uId, cId)

    // Următoarea linie ar eșua IMEDIAT la compilare (mismatched types!):
    // serviciu.proceseazaComanda(cId, uId)
}

Ce Generează Compilatorul în Bytecode?

La momentul compilării în bytecode JVM, clasa UtilizatorId este ștearsă complet (Inlined)! Metoda proceseazaComanda se transformă în cod mașină nativ primind doi întregi primitivi simpli (long userId, long comandaId). Obțineți siguranță absolută a tipurilor la compilare cu zero alocări de memorie pe Heap la runtime!