JDK 28 Value Classes Promise Efficiency, But Experts Warn of Performance Pitfalls
Project Valhalla's latest preview feature enables memory flattening, yet requires 'compiler sympathy' to avoid unexpected slowdowns.
Java is evolving its fundamental type system with the introduction of value classes in JDK 28. This shift aims to bridge the long-standing gap between primitive types and objects, allowing developers to achieve high-performance memory layouts without sacrificing the benefits of object-oriented programming.
As part of JEP 401, value classes arrive as a preview feature in JDK 28. These classes enable the Java Virtual Machine (JVM) to optimize memory layout through a process known as flattening, which removes the overhead associated with object identity. By eliminating unnecessary indirection, the JVM can store data more densely in memory, significantly reducing pressure on the garbage collector and improving cache locality.
The Valhalla Vision
This development is a cornerstone of Project Valhalla, a multi-year effort to modernize Java's type system. Historically, Java has maintained a rigid divide: primitives offer speed and efficiency but lack polymorphism, while objects provide flexibility but incur a performance penalty due to reference-based memory management. Value classes are designed to provide the best of both worlds, offering the polymorphism and generics of objects with the memory characteristics of primitives.
The Risk of Performance Degradation
Despite the potential gains, developer Johan Sjölen warns that value classes are not a guaranteed performance upgrade. Sjölen argues that some developers mistakenly believe value classes provide a performance floor, assuming they will only ever improve speed or, at worst, leave it unchanged. "I worry that there is a belief that ordinary classes give you a floor on performance, and that value classes will do their best to raise you above that floor, but won’t ever take you below it," Sjölen wrote on his blog. "Unfortunately, that is not true."
According to Sjölen, incorrect implementation can actually lead to performance drops. This occurs when the JVM is forced to use reference representations in contexts where a flattened representation would have been faster, effectively introducing new inefficiencies into the code.
The Need for Compiler Sympathy
Because Java remains a highly dynamic language—characterized by runtime class loading and type erasure—the compiler cannot always automatically determine the most efficient memory representation. This creates a need for what Sjölen calls "compiler sympathy."
Compiler sympathy requires developers to understand how the JVM handles these new types and to write code that actively enables the JVM to apply optimizations. Rather than adopting a "Value all the classes!" mentality, developers must be strategic about where value classes are applied to ensure the JVM can actually flatten the data structures as intended.
What to Watch
As JEP 401 moves through its preview phase, the industry will be watching how these optimizations perform in real-world, high-scale data environments. The primary challenge remains the balance between Java's dynamic nature and the static requirements of memory flattening. Developers adopting JDK 28 should prioritize profiling and benchmarking to ensure their use of value classes is truly sympathetic to the JVM's internal mechanics.