JEP 401 Value Classes Target JDK 28: Valhalla's Answer to Record Performance Limits
Project Valhalla has moved significantly closer to production reality. JEP 401 Value Classes, now integrated into OpenJDK mainline with preview status, introduces a specialized abstraction mechanism that addresses fundamental performance limitations—a critical advance for teams building latency-sensitive backend services.
The distinction matters conceptually. Records, introduced in JDK 16, provide transparent immutable carriers for data. But they remain objects: they live on the heap, carry object headers, and impose garbage collection pressure. JIT compilers can optimize records to a point, but escape analysis only succeeds when allocation can be entirely eliminated—a narrow set of workloads. Value classes take a different approach. They are declared as non-identity types, meaning the JVM treats them more like primitive types than traditional objects. Two value class instances with identical field values are considered equal by the runtime itself, not just by overridden equality methods. More importantly, they can be flattened directly into containing objects or arrays, eliminating allocation overhead altogether.
The performance implications are significant for bulk operations. In tight loops processing collections of small numeric or coordinate tuples—common in financial calculations, gaming engines, or machine learning inference—value classes can substantially reduce heap allocations compared to boxed primitives or records. The JIT compiler gains deeper optimization opportunities because it doesn’t need to prove that an allocation can be discarded; the value class is designed to be stack-allocated or inlined. This translates to lower garbage collection pause times and higher throughput for systems where object creation was previously a bottleneck.
The trade-off is explicit and intentional. Value classes sacrifice identity and mutability by design. You cannot synchronize on a value class instance, cannot use identity-based comparison, and cannot define mutable fields—rules that prevent developers from accidentally using value classes in contexts where their performance assumptions would be violated. This strictness means the JVM can make stronger guarantees about memory layout and access patterns. Records remain the better choice for most data-carrying use cases where identity or mutable state matters; value classes target the specific, performance-critical subset where those properties are liabilities, not features.
Integration into the mainline OpenJDK with preview status signals that the design has matured beyond experimentation. Preview features allow production code to adopt and stress-test them before finalization, giving the ecosystem time to build tooling, libraries, and patterns around value classes. For backend teams already using records extensively, the decision will be selective: value classes will replace records in hot paths where allocation or garbage collection pressure is measurable. This is not a wholesale language redesign but a precise tool for a well-defined problem—which is precisely what makes it valuable.
🔗 Source: Java Code Geeks