Una de las esperas más largas de la historia de Java se está terminando. El 15 de junio de 2026, la ingeniera de Oracle Lois Foltan confirmó que JEP 401: Value Classes and Objects —el corazón de Project Valhalla— se integra al repositorio principal de OpenJDK con destino a JDK 28, que sale en marzo de 2027. Llega como feature de preview (hay que activarla con --enable-preview), pero después de un proyecto que arrancó en 2014, ver value classes en la rama mainline es un acontecimiento. Foltan lo describió como un cambio «extremadamente grande»: el pull request suma más de 197.000 líneas de código en 1.816 archivos, al punto que se les pidió al resto de los committers evitar commits grandes para no romper la integración.
«Code like a class, work like an int»
Esa frase resume todo Valhalla. Desde siempre Java te obliga a elegir: o usás una clase (segura, legible, orientada a objetos) o usás un primitivo como int (rápido, denso en memoria). El precio de la clase es la identidad: cada objeto es único por su posición en memoria, no por su contenido. Por eso dos LocalDate que representan la misma fecha dan false al compararlas con ==, aunque tengan exactamente los mismos campos. Las value classes rompen esa regla de 1995: son objetos sin identidad, donde lo único que importa son los valores de sus campos. En criollo, == pasa a comparar contenido (substitutability) en vez de posición de memoria, y eso le abre la puerta a la JVM para optimizar de forma agresiva.
El problema real: millones de objetos chiquitos matando al GC
Acá es donde el tema pega fuerte para quienes trabajamos con datos. Hoy un array de un millón de objetos Point es, en la práctica, un millón de punteros que apuntan a un millón de objetos dispersos en el heap, cada uno con su header de metadata. Eso es presión sobre el garbage collector, saltos de memoria constantes y pésima localidad de caché. Valhalla ataca esto por dos lados: scalarization, donde el compilador JIT descompone la referencia en sus campos y elimina la asignación en el heap; y flattening, donde los valores se guardan inline dentro del array o del campo contenedor, en bloque contiguo. Ese Point[1.000.000] deja de ser un millón de objetos dispersos y pasa a ser un bloque compacto, con densidad de memoria tipo primitivo pero conservando la abstracción de clase.
Para el público que toca fintech, procesamiento de datos, machine learning, gráficos o HPC, esto es exactamente el cuello de botella que veníamos sufriendo: estructuras inmutables y chicas (montos, coordenadas, fechas, vectores) que se multiplican por millones y le hacen pasar un mal rato al GC. Menos punteros, menos pausas de GC, mejor uso de la línea de caché.
Qué entra en JDK 28 y qué todavía no
Lo concreto que vas a poder usar: declarar value class y value record; la migración bajo preview de clases «value-based» que ya existen en el JDK —entre ellas los wrappers como Integer, Long y Double—; scalarization y flattening para las clases que califican; y boxing más barato. Ojo con un par de cambios de semántica: synchronized sobre un value object tira IdentityException (no tienen identidad, no se pueden usar como lock), y == ahora compara campos recursivamente.
Lo que no llega todavía y conviene tener claro para no hacerse falsas expectativas: los null-restricted types (value classes no nulleables) quedan para otro JEP; los generics especializados también, así que ArrayList<Point> sigue materializando objetos en el heap por type erasure —el flattening por ahora aplica a arrays directos y campos, no a colecciones genéricas—; y faltan los encodings atómicos de 128 bits. El propio Brian Goetz, Java Language Architect, bajó la espuma: esto es «solo la primera parte de Valhalla» y probablemente siga en preview a lo largo de JDK 29 (septiembre de 2027), el próximo LTS donde se espera que la cosa madure.
Qué cambia para los que escribimos Java
La buena noticia es que la mayoría del código existente sigue compilando: los breaking changes solo aparecen donde dependés explícitamente de la identidad (sincronizar sobre el objeto, comparar referencias). La movida real para developers y mantenedores de librerías es empezar a pensar en términos de «este tipo no tiene identidad» y limpiar la null pollution para quedar listos cuando lleguen los generics especializados. No es algo para meter en producción mañana —es preview—, pero sí es el momento de bajarse un early-access build, marcar tus tipos de dominio inmutables como value y medir. Para los que venimos arrastrando aplicaciones data-intensive en la región, esta es la base sobre la que se va a construir una década de mejoras de performance en la JVM. ¿Ya tenés tipos en tu código que gritan «yo debería ser un value class»? ¿Lo vas a probar en cuanto salga el preview? Te leemos en los comentarios.


